我有一个插件架构,我在其中调用动态库中的函数,它们返回给我一个 char*
这就是答案,它会在稍后阶段使用。
这是插件函数的签名:
char* execute(ALLOCATION_BEHAVIOR* free_returned_value, unsigned int* length);
其中 ALLOCATION_BEHAVIOR
必须是:DO_NOT_FREE_ME
、FREE_ME
、DELETE_ME
插件所在的位置(在库中)告诉我插件如何分配它刚刚返回的字符串: DO_NOT_FREE_ME
告诉我,这是一个我不应该接触的变量(例如 const static char*
永远不会改变) FREE_ME
告诉我应该使用 free()
来释放返回的值, DELETE_ME
告诉我使用 delete[ ]
以消除内存泄漏。
显然,我不信任插件,所以我希望能够检查他是否告诉我 free()
变量,确实它是可以真正被释放的东西... 这可能在 Linux/Windows 上使用当今的 C/C++ 技术吗?
最佳答案
区分 malloc/free
和 new/delete
通常是不可能的,至少不是以可靠和/或可移植的方式。更何况 new
在许多实现中只是简单地包装了 malloc
。
以下区分堆/堆栈的替代方法均未经过测试,但它们应该都有效。
Linux:
- Luca Tettananti提出的解决方案,解析
/proc/self/maps
得到栈的地址范围。 - 作为启动时的第一件事,
克隆
你的进程,这意味着提供一个堆栈。既然你提供了它,你就会自动知道它在哪里。 - 调用 GCC 的
__builtin_frame_address
函数,增加 level 参数直到它返回 0。然后你就知道了深度。现在再次以最大级别调用__builtin_frame_address
,并以 0 级别调用一次。堆栈中的任何内容都必须位于这两个地址之间。 sbrk(0)
作为启动时的第一件事,并记住该值。每当您想知道堆上是否有东西时,再次sbrk(0)
-- 堆上的东西必须在两个值之间。请注意,这不适用于使用内存映射进行大分配的分配器。
知道堆栈的位置和大小(备选方案 1 和 2),确定地址是否在该范围内就很简单了。如果不是,则必然是“堆”(除非有人试图变得 super 聪明,并给你一个指向静态全局的指针,或者一个函数指针,等等......)。
Windows:
- 使用 CaptureStackBackTrace ,堆栈中的任何内容都必须位于返回的指针数组的第一个和最后一个元素之间。
- 如上使用 GCC-MinGW(和
__builtin_frame_address
,应该可以正常工作)。 - 使用
GetProcessHeaps
和HeapWalk
检查每个分配的 block 是否匹配。如果没有与任何堆匹配,则它因此被分配到堆栈上(......或内存映射,如果有人试图对你 super 聪明)。 - 使用
HeapReAlloc
和HEAP_REALLOC_IN_PLACE_ONLY
并且大小完全相同。如果失败,则不会在堆上分配从给定地址开始的内存块。如果它“成功”了,那就是空操作。 - 使用
GetCurrentThreadStackLimits
(仅限 Windows 8/2012) - 调用
NtCurrentTeb()
(或读取fs:[18h]
)并使用字段StackBase
和StackLimit
返回的 TEB。
关于c++ - 如何判断返回的指针是在栈上还是堆上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16709946/