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
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:
- 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.
- You can only use it if you know for sure on which heap the memory was allocated (in case it's a heap memory).