如何确定返回的指针是在堆栈还是堆上

时间:2023-05-08
本文介绍了如何确定返回的指针是在堆栈还是堆上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

限时送ChatGPT账号..

我有一个插件架构,我在动态库中调用函数,然后他们返回一个 char* 这是答案,它会在以后的某个阶段使用.

I have a plugin architecture, where I call functions in a dynamic library and they return me a char* which is the answer, it is used at some later stage.

这是一个插件函数的签名:

This is the signature of a plugin function:

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

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

where ALLOCATION_BEHAVIOR must be either: DO_NOT_FREE_ME, FREE_ME, DELETE_ME where the plugin (in the library) tells me how the plugin allocated the string it has just returned: DO_NOT_FREE_ME tells me, this is a variable I'm not supposed to touch (such as a const static char* which never changes) FREE_ME tells me I should use free() to free the returned value and DELETE_ME tells me to use delete[] to get rid of the memory leaks.

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

Obviously, I don't trust the plugins, so I would like to be able to check that if he tells me to free() the variable, indeed it is something that can really be freed ... Is this possible using todays' C/C++ technology on Linux/Windows?

推荐答案

区分 malloc/freenew/delete 通常是不可能的,至少在一个可靠和/或便携的方式.更何况 new 在许多实现中都简单地包装了 malloc.

Distinguishing between malloc/free and new/delete is generally not possible, at least not in a reliable and/or portable way. Even more so as new simply wrapps malloc anyway in many implementations.

以下区分堆/堆栈的替代方案均未经过测试,但它们应该都可以工作.

None of the following alternatives to distinguish heap/stack have been tested, but they should all work.

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. Solution proposed by Luca Tettananti, parse /proc/self/maps to get the address range of the stack.
  2. As the first thing at startup, clone your process, this implies supplying a stack. Since you supply it, you automatically know where it is.
  3. Call GCC's __builtin_frame_address function with increasing level parameter until it returns 0. You then know the depth. Now call __builtin_frame_address again with the maximum level, and once with a level of 0. Anything that lives on the stack must necessarily be between these two addresses.
  4. sbrk(0) as the first thing at startup, and remember the value. Whenever you want to know if something is on the heap, sbrk(0) again -- something that's on the heap must be between the two values. Note that this will not work reliably with allocators that use memory mapping for large allocations.

知道堆栈的位置和大小(备选方案 1 和 2),找出地址是否在该范围内就很简单了.如果不是,则必然是堆"(除非有人试图变得超级聪明并为您提供指向静态全局或函数指针等的指针......).

Knowing the location and size of the stack (alternatives 1 and 2), it's trivial to find out if an address is within that range. If it's not, is necessarily "heap" (unless someone tries to be super smart-ass and gives you a pointer to a static global, or a function pointer, or such...).

Windows:

  1. 使用 CaptureStackBackTrace,任何活的堆栈上的元素必须在返回的指针数组的第一个和最后一个元素之间.
  2. 使用 GCC-MinGW(和 __builtin_frame_address,它应该可以正常工作)如上.
  3. 使用GetProcessHeapsHeapWalk 检查每个分配的块是否匹配.如果没有任何堆匹配,那么它就会被分配到堆栈上(...或者内存映射,如果有人试图对你超级聪明).
  4. 使用 HeapReAllocHEAP_REALLOC_IN_PLACE_ONLY 并且大小完全相同.如果失败,则不会在堆上分配从给定地址开始的内存块.如果它成功",则为空操作.
  5. 使用 GetCurrentThreadStackLimits(仅限 Windows 8/2012)
  6. 调用 NtCurrentTeb()(或读取 fs:[18h])并使用 StackBaseStackLimit 字段> 返回的 TEB.
  1. Use CaptureStackBackTrace, anything living on the stack must be between the returned pointer array's first and last element.
  2. Use GCC-MinGW (and __builtin_frame_address, which should just work) as above.
  3. Use GetProcessHeaps and HeapWalk to check every allocated block for a match. If none match for none of the heaps, it's consequently allocated on the stack (... or a memory mapping, if someone tries to be super-smart with you).
  4. Use HeapReAlloc with HEAP_REALLOC_IN_PLACE_ONLY and with exactly the same size. If this fails, the memory block starting at the given address is not allocated on the heap. If it "succeeds", it is a no-op.
  5. Use GetCurrentThreadStackLimits (Windows 8 / 2012 only)
  6. Call NtCurrentTeb() (or read fs:[18h]) and use the fields StackBase and StackLimit of the returned TEB.

这篇关于如何确定返回的指针是在堆栈还是堆上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:C++虚函数表内存开销 下一篇:在处理易失性内存位置时,编译器必须遵循哪些规则?

相关文章