问题描述
我有一个插件架构,我在动态库中调用函数,然后他们返回一个 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_ME
、FREE_ME
、DELETE_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/free
和 new/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:
- Luca Tettananti 提出的解决方案,解析
/proc/self/maps
得到栈的地址范围. - 作为启动时的第一件事,
克隆
你的进程,这意味着提供一个堆栈.既然你提供了它,你就会自动知道它在哪里. - 调用 GCC 的
__builtin_frame_address
函数并增加 level 参数,直到它返回 0.然后你就知道深度了.现在再次使用最大级别调用__builtin_frame_address
一次,级别为 0.任何位于堆栈中的内容都必须在这两个地址之间. sbrk(0)
作为启动时的第一件事,并记住该值.每当你想知道堆上是否有东西时,再次sbrk(0)
—— 堆上的东西必须在两个值之间.请注意,对于使用内存映射进行大量分配的分配器,这将无法可靠地工作.
- Solution proposed by Luca Tettananti, parse
/proc/self/maps
to get the address range of the stack. - As the first thing at startup,
clone
your process, this implies supplying a stack. Since you supply it, you automatically know where it is. - 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. 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:
- 使用 CaptureStackBackTrace,任何活的堆栈上的元素必须在返回的指针数组的第一个和最后一个元素之间.
- 使用 GCC-MinGW(和
__builtin_frame_address
,它应该可以正常工作)如上. - 使用
GetProcessHeaps
和HeapWalk
检查每个分配的块是否匹配.如果没有任何堆匹配,那么它就会被分配到堆栈上(...或者内存映射,如果有人试图对你超级聪明). - 使用
HeapReAlloc
和HEAP_REALLOC_IN_PLACE_ONLY
并且大小完全相同.如果失败,则不会在堆上分配从给定地址开始的内存块.如果它成功",则为空操作. - 使用
GetCurrentThreadStackLimits
(仅限 Windows 8/2012) - 调用
NtCurrentTeb()
(或读取fs:[18h]
)并使用StackBase
和StackLimit
字段> 返回的 TEB.
- Use CaptureStackBackTrace, anything living on the stack must be between the returned pointer array's first and last element.
- Use GCC-MinGW (and
__builtin_frame_address
, which should just work) as above. - Use
GetProcessHeaps
andHeapWalk
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). - Use
HeapReAlloc
withHEAP_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. - Use
GetCurrentThreadStackLimits
(Windows 8 / 2012 only) - Call
NtCurrentTeb()
(or readfs:[18h]
) and use the fieldsStackBase
andStackLimit
of the returned TEB.
这篇关于如何确定返回的指针是在堆栈还是堆上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!