c++ - 如何判断返回的指针是在栈上还是堆上

标签 c++ c memory

我有一个插件架构,我在其中调用动态库中的函数,它们返回给我一个 char* 这就是答案,它会在稍后阶段使用。

这是插件函数的签名:

char* execute(ALLOCATION_BEHAVIOR* free_returned_value, unsigned int* length);

其中 ALLOCATION_BEHAVIOR 必须是:DO_NOT_FREE_MEFREE_MEDELETE_ME 插件所在的位置(在库中)告诉我插件如何分配它刚刚返回的字符串: DO_NOT_FREE_ME 告诉我,这是一个我不应该接触的变量(例如 const static char*永远不会改变) FREE_ME 告诉我应该使用 free() 来释放返回的值, DELETE_ME 告诉我使用 delete[ ] 以消除内存泄漏。

显然,我不信任插件,所以我希望能够检查他是否告诉我 free() 变量,确实它是可以真正被释放的东西... 这可能在 Linux/Windows 上使用当今的 C/C++ 技术吗?

最佳答案

区分 malloc/freenew/delete 通常是不可能的,至少不是以可靠和/或可移植的方式。更何况 new 在许多实现中只是简单地包装了 malloc

以下区分堆/堆栈的替代方法均未经过测试,但它们应该都有效。

Linux:

  1. Luca Tettananti提出的解决方案,解析/proc/self/maps得到栈的地址范围。
  2. 作为启动时的第一件事,克隆你的进程,这意味着提供一个堆栈。既然你提供了它,你就会自动知道它在哪里。
  3. 调用 GCC 的 __builtin_frame_address 函数,增加 level 参数直到它返回 0。然后你就知道了深度。现在再次以最大级别调用 __builtin_frame_address,并以 0 级别调用一次。堆栈中的任何内容都必须位于这两个地址之间。
  4. sbrk(0) 作为启动时的第一件事,并记住该值。每当您想知道堆上是否有东西时,再次sbrk(0) -- 堆上的东西必须在两个值之间。请注意,这不适用于使用内存映射进行大分配的分配器。

知道堆栈的位置和大小(备选方案 1 和 2),确定地址是否在该范围内就很简单了。如果不是,则必然是“堆”(除非有人试图变得 super 聪明,并给你一个指向静态全局的指针,或者一个函数指针,等等......)。

Windows:

  1. 使用 CaptureStackBackTrace ,堆栈中的任何内容都必须位于返回的指针数组的第一个和最后一个元素之间。
  2. 如上使用 GCC-MinGW(和 __builtin_frame_address,应该可以正常工作)。
  3. 使用 GetProcessHeapsHeapWalk 检查每个分配的 block 是否匹配。如果没有与任何堆匹配,则它因此被分配到堆栈上(......或内存映射,如果有人试图对你 super 聪明)。
  4. 使用 HeapReAllocHEAP_REALLOC_IN_PLACE_ONLY 并且大小完全相同。如果失败,则不会在堆上分配从给定地址开始的内存块。如果它“成功”了,那就是空操作。
  5. 使用 GetCurrentThreadStackLimits(仅限 Windows 8/2012)
  6. 调用 NtCurrentTeb()(或读取 fs:[18h])并使用字段 StackBaseStackLimit 返回的 TEB。

关于c++ - 如何判断返回的指针是在栈上还是堆上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16709946/

相关文章:

c++ - PEM_read_X509() 以代码 0 退出

c - 执行直接操作时,输出值与函数内作为参数接收的值不同

python - 在 Python 中计算内存碎片

c++ - basic_string 预期初始化程序编译错误

c++ - 将二维 vector 转换为二维数组

c++ - 使用局部静态变量调用函数

c - 在 makefile 中,如何使规则中的变量成为全局变量?

c - 二维数组中间的内存地址越界?

静态数组的正确大小

Python身份: Multiple personality disorder,需要代码收缩