views:

156

answers:

7

I know that memory alloced using new, gets its space in heap, and so we need to delete it before program ends, to avoid memory leak.

Let's look at this program...

Case 1:

char *MyData = new char[20];
_tcscpy(MyData,"Value");
.
.
.
delete[] MyData; MyData = NULL;


Case 2:
char *MyData = new char[20];
MyData = "Value";
.
.
.
delete[] MyData; MyData = NULL;

In case 2, instead of allocating value to the heap memory, it is pointing to a string literal.

Now when we do a delete it would crash, AS EXPECTED, since it is not trying to delete a heap memory. Is there a way to know where the pointer is pointing to heap or stack?

By this the programmer

  • Will not try to delete any stack memory
  • He can investigate why does this ponter, that was pointing to a heap memory initially, is made to refer local literals? What happened to the heap memory in the middle? Is it being made to point by another pointer and delete elsewhere and all that?
+1  A: 

I think there is no (easy) way how to tell where the memory is allocated (you might be able to determine it using a debugger, perhaps, but that is obviously not what you want). The bottom line is: never do the thing you did in case 2.

PeterK
+2  A: 

As soon as you need that knowledge you have already lost. Why? Because then even if you omit the wrong delete[], you still have a memory leak.

The one who creates the memory should always be the one who deletes it. If at some occasion a pointer might get lost (or overwritten) then you have to keep a copy of it for the proper delete.

ypnos
@ypnos: Yes, as you rightly said, I have pointed out that there is memory leak in the program. My question is, do we have any ways to investigate whether the pointer that was refering to one heap memory got changed some where and what happened to the older one. For sample programs like this, it is easy to spot. But for bigger maintenance projects its tedious. You would agree if at all you happed to work on maintenance projects.
AKN
This is why we use std::strings, std::vectors, avoid pointers when not needed, and if really needed we use smart pointers
Nikko
AKN: Nikko raises a good point here. Perhaps as part of your maintainance work you will have to refactor the code to use smart pointers or c++ strings. At least that's what I do when I have to incorporate old C code into our framework.
ypnos
A: 

In case 2, MyData = "Value" causes a memory leak since there is no longer a reference to the memory returned from new.

travis0xff
+2  A: 

There is no way in Standard C++ of determining whether a pointer points to dynamically allocated memory or not. And note that string literals are not allocated on the stack.

anon
@Neil: "String literals are not allocated on the stack". If not stack, can you please tell where does it go?
AKN
@AKN The Strandard doesn't say. It does say that the lifetime of a literal is that of the program, so they can't be placed on the stack.
anon
@AKN string literals are part of the executable. They are in the text segment along with the code (depending on binary format of course).
JeremyP
AKN
"stack" is a slightly fuzzy term, but the important part is that the following code is perfectly OK: `const char* foo() { return "Foo"; }` The string `"Foo"` doesn't disappear when `foo()` returns.
MSalters
+2  A: 

As most of the users said here there's no standard way to discover which memory you're dealing with.

Also, as many users pointed out, it;s a kinda perverted situation where you pass a pointer to a function which should delete it automatically if it's allocated on heap.

But if you insist, nevertheless there are some ways to discover which memory belongs to which type.

You actually deal with 3 types of memory

  • Stack
  • Heap
  • Global

For instance:

char* p = new char[10]; // p is a pointer, points to heap-allocated memory

char* p = "Hello, world!"; // p is a pointer, points to the global memory

char p[] = "Hello, world!"; // p is a buffer allocated on the stack and initialized with the string

Now let's distinguish them. I'll describe this in terms of Windows API and x86 assembler (since this is what I know :))

Let's start from stack memory.

bool IsStackPtr(PVOID pPtr)
{
    // Get the stack pointer
    PBYTE pEsp;
    _asm {
        mov pEsp, esp
    };

    // Query the accessible stack region
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pEsp, &mbi, sizeof(mbi)));

    // the accessible stack memory starts at mbi.BaseAddress and lasts for mbi.RegionSize
    return (pPtr >= mbi.BaseAddress) && (pPtr < PBYTE(mbi.BaseAddress) + mbi.RegionSize);
}

If the pointer is allocated on the stack of another thread you should get its stack pointer by GetThreadContext instead of just taking the EIP register value.

Global memory

bool IsGlobalPtr(PVOID pPtr)
{
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pPtr, &mbi, sizeof(mbi)));

    // Global memory allocated (mapped) at once for the whole executable
    return mbi.AllocationBase == GetModuleHandle(NULL);
}

If you're writing a DLL you should put its module handle (which is actually its base mapping pointer) instead of GetModuleHandle(NULL).

Heap

Theoretically you may assume that if the memory is neither global nor stack - it's allocated on heap.

But there's is actually a big ambiguity here.

You should know that there're different implementations of the heap (such as raw Windows heap accessed by HeapAlloc/HeapFree, or CRT-wrapped malloc/free or new/delete).

You may delete such a block via delete operator only if you know for sure it was either stack/global pointer or it was allocated via new.

In conclusion:

  1. It's a kinda pervert trick. Should not be used generally. Better to provide some extra information with the pointer which tells how to release it.
  2. You can only use it if you know for sure on which heap the memory was allocated (in case it's a heap memory).
valdo
Believe it or not, not everyone is using Windows.
anon
Alright, I don't insist on using Windows. There're probably ways to do this on Linux too.
valdo
It misses memory-mapped files, including the anonymous (pagefile) mapping, and memory you got from others (e.g. COM strings). And threadd-local variables. And perhaps even more.
MSalters
Of course. Not to mention that "heap" doesn't have to be a standard C/C++ heap.I mentioned it.
valdo
+2  A: 

Is there a way to know where the pointer is pointing to heap or stack?

You can know this only if you remember it at the point of allocation. What you do in this case is to store your pointers in smart pointer classes and store this in the class code.

If you use boost::shared_ptr as an example you can do this:

template<typename T> void no_delete(T* ptr) { /* do nothing here */ }

class YourDataType; // defined elsewhere
boost::shared_ptr<YourDataType> heap_ptr(new YourDataType()); // delete at scope end

YourDataType  stackData;
boost::shared_ptr<YourDataType> stack_ptr(&stackData, &no_delete); // never deleted
utnapistim
A: 

There is no easy way or standard way for doing this. You can intercept the heap allocation function(s) and put each memory allocated zone in a list. Your "IsHeap" function should check if the zone passed to the function is the one from the list. This is just a hint - it is almost impossible to do this in a cross-platform manner.

But then again - why would you need that?

Iulian Şerbănoiu