正如大多数用户所说,没有标准的方法来发现您正在处理的内存。
此外,正如许多用户指出的那样,这是一种变态的情况,您将指针传递给一个函数,如果它是在堆上分配的,该函数应该自动删除它。
但是,如果您坚持,仍然有一些方法可以发现哪些记忆属于哪种类型。
您实际上处理了 3 种类型的内存
例如:
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
现在让我们区分它们。我将用 Windows API 和 x86 汇编器来描述这一点(因为这是我所知道的 :))
让我们从堆栈内存开始。
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);
}
如果指针分配在另一个线程的堆栈上,您应该获取它的堆栈指针,GetThreadContext
而不是仅仅获取EIP
寄存器值。
全局内存
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);
}
如果你正在编写一个 DLL,你应该把它的模块句柄(实际上是它的基本映射指针)而不是GetModuleHandle(NULL)
.
堆
从理论上讲,您可以假设如果内存既不是全局内存也不是堆栈内存 - 它是在堆上分配的。
但实际上这里有一个很大的歧义。
您应该知道堆有不同的实现(例如由HeapAlloc
/访问的原始 Windows 堆HeapFree
,或 CRT 包装的malloc
/free
或new
/ delete
)。
只有当您delete
确定它是堆栈/全局指针或者它是通过new
.
综上所述:
- 这是一种变态的把戏。一般不宜使用。最好用指针提供一些额外的信息,告诉如何释放它。
- 如果您确定内存分配在哪个堆上(如果它是堆内存),则只能使用它。