xcode 如何在 OS X 下覆盖 malloc()、calloc()、free() 等?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/929893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 18:35:25  来源:igfitidea点击:

how can i override malloc(), calloc(), free() etc under OS X?

xcodemacosmallocoverriding

提问by

Assuming the latest XCode and GCC, what is the proper way to override the memory allocation functions (I guess operator new/delete as well). The debugging memory allocators are too slow for a game, I just need some basic stats I can do myself with minimal impact.

假设最新的 XCode 和 GCC,覆盖内存分配函数的正确方法是什么(我猜也是 operator new/delete)。调试内存分配器对于游戏来说太慢了,我只需要一些基本的统计数据,我可以在最小的影响下自己完成。

I know its easy in Linux due to the hooks, and this was trivial under codewarrior ten years ago when I wrote HeapManager.

由于钩子,我知道它在 Linux 中很容易,十年前当我编写 HeapManager 时,这在 codewarrior 下是微不足道的。

Sadly smartheap no longer has a mac version.

遗憾的是 smartheap 不再有 mac 版本。

回答by sam hocevar

I would use library preloading for this task, because it does not require modification of the running program. If you're familiar with the usual Unix way to do this, it's almost a matter of replacing LD_PRELOAD with DYLD_INSERT_LIBRARIES.

我会为此任务使用库预加载,因为它不需要修改正在运行的程序。如果您熟悉执行此操作的常用 Unix 方式,那么几乎可以用 DYLD_INSERT_LIBRARIES 替换 LD_PRELOAD。

First step is to create a library with code such as this, then build it using regular shared library linking options (gcc -dynamiclib):

第一步是使用这样的代码创建一个库,然后使用常规共享库链接选项 ( gcc -dynamiclib)构建它:

void *malloc(size_t size)
{
    void * (*real_malloc)(size_t);
    real_malloc = dlsym(RTLD_NEXT, "malloc");

    fprintf(stderr, "allocating %lu bytes\n", (unsigned long)size);
    /* Do your stuff here */

    return real_malloc(size);
}

Note that if you also divert calloc()and its implementation calls malloc(), you may need additional code to check how you're being called. C++ programs should be pretty safe because the newoperator calls malloc()anyway, but be aware that no standard enforces that. I have never encountered an implementation that didn't use malloc(), though.

请注意,如果您还转移calloc()及其实现调用malloc(),您可能需要额外的代码来检查您是如何被调用的。C++ 程序应该非常安全,因为无论如何new操作符都会调用malloc(),但要注意没有标准强制执行这一点。不过,我从未遇到过不使用 的实现malloc()

Finally, set up the running environment for your program and launch it (might require adjustments depending on how your shell handles environment variables):

最后,为您的程序设置运行环境并启动它(可能需要根据您的 shell 处理环境变量的方式进行调整):

export DYLD_INSERT_LIBRARIES=./yourlibrary.dylib
export DYLD_FORCE_FLAT_NAMESPACE=1
yourprogram --yourargs

See the dyld manual pagefor more information about the dynamic linker environment variables.

有关动态链接器环境变量的更多信息,请参阅dyld 手册页

This method is pretty generic. There are limitations, however:

这种方法非常通用。但是也有限制:

  • You won't be able to divert direct system calls
  • If the application itself tricks you by using dlsym()to load malloc's address, the call won't be diverted. Unless, however, you trick it back by also diverting dlsym!
  • 您将无法转移直接系统调用
  • 如果应用程序本身通过使用dlsym()加载malloc的地址来欺骗您,则不会转移呼叫。但是,除非您还通过转移来欺骗它dlsym

回答by Alex Martelli

The malloc_default_zonetechnique mentioned at http://lists.apple.com/archives/darwin-dev/2005/Apr/msg00050.htmlappears to still work, see e.g. http://code.google.com/p/fileview/source/browse/trunk/fileview/fv_zone.cpp?spec=svn354&r=354for an example use that seems to be similar to what you intend.

http://lists.apple.com/archives/darwin-dev/2005/Apr/msg00050.htmlmalloc_default_zone提到的技术似乎仍然有效,例如参见http://code.google.com/p/fileview/source/浏览/trunk/fileview/fv_zone.cpp?spec=svn354&r=354的示例用途似乎与您的意图相似。

回答by bkdc

After much searching (here included) and issues with 10.7 I decided to write a blog post about this topic: How to set malloc hooks in OSX Lion

经过大量搜索(此处包括)和 10.7 的问题后,我决定写一篇关于这个主题的博客文章:如何在 OSX Lion 中设置 malloc 钩子

You'll find a few good links at the end of the post with more information on this topic.

您会在文章末尾找到一些很好的链接,其中包含有关此主题的更多信息。

The basic solution:

基本解决方案:

malloc_zone_t *dz=malloc_default_zone();
if(dz->version>=8)
{
    vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ | VM_PROT_WRITE);//remove the write protection
}
original_free=dz->free;
dz->free=&my_free; //this line is throwing a bad ptr exception without calling vm_protect first
if(dz->version==8)
{
    vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ);//put the write protection back
}

回答by monitorjbl

This is an old question, but I came across it while trying to do this myself. I got curious about this topic for a personal project I was working on, mainly to make sure that what I thought was automatically deallocated was being properly deallocated. I ended up writing a C++ implementation to allow me to track the amount of allocated heap and report it out if I so chose.

这是一个老问题,但我在尝试自己做这件事时遇到了它。我对我正在从事的个人项目的这个主题感到好奇,主要是为了确保我认为自动释放的内容被正确释放。我最终编写了一个 C++ 实现,以允许我跟踪分配的堆的数量并在我选择时报告出来。

https://gist.github.com/monitorjbl/3dc6d62cf5514892d5ab22a59ff34861

https://gist.github.com/monitorjbl/3dc6d62cf5514892d5ab22a59ff34861

As the name notes, this is OSX-specific. However, I was able to do this on Linux environments using the malloc_usable_size

顾名思义,这是特定于 OSX 的。但是,我能够在 Linux 环境中使用malloc_usable_size

Example

例子

#define MALLOC_DEBUG_OUTPUT
#include "malloc_override_osx.hpp"

int main(){
   int* ip = (int*)malloc(sizeof(int));
   double* dp = (double*)malloc(sizeof(double));

   free(ip);
   free(dp);
}

Building

建筑

$ clang++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
          -pipe -stdlib=libc++ -std=gnu++11 -g -o test test.cpp
$ ./test
0x7fa28a403230 -> malloc(16) -> 16
0x7fa28a403240 -> malloc(16) -> 32
0x7fa28a403230 -> free(16) -> 16
0x7fa28a403240 -> free(16) -> 0

Hope this helps someone else out in the future!

希望这可以帮助其他人在未来!

回答by sholsapp

Check out Emery Berger's -- the author of the Hoard memory allocator's -- approach for replacing the allocator on OSX at https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp(and a few other files you can trace yourself by following the includes).

https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp(和一些您可以通过遵循包含来跟踪自己的其他文件)。

This is complementary to Alex's answer, but I thought this example was more to-the-point of replacing the system provided allocator.

这是对 Alex 回答的补充,但我认为这个例子更接近于替换系统提供的分配器。

回答by sholsapp

If the basic stats you need can be collected in a simple wrapper, a quick (and kinda dirty) trick is just using some #definemacro replacement.

如果您需要的基本统计信息可以收集在一个简单的包装器中,那么一个快速(而且有点脏)的技巧就是使用一些#define宏替换。

void* _mymalloc(size_t size)
{
    void* ptr = malloc(size);

    /* do your stat work? */

    return ptr;
}

and

#define malloc(sz_) _mymalloc(sz_)

Note: if the macro is defined beforethe _mymalloc definition it will end up replacing the malloc call inside that function leaving you with infinite recursion... so ensure this isn't the case. You might want to explicitly #undefit before that function definition and simply (re)define it afterward depending on where you end up including it to hopefully avoid this situation.

注意:如果宏是_mymalloc 定义之前定义的,它将最终替换该函数内的 malloc 调用,从而使您具有无限递归......所以确保不是这种情况。您可能希望#undef在该函数定义之前显式地定义它,然后根据最终包含它的位置简单地(重新)定义它以希望避免这种情况。

回答by Joshua

I think if you define a malloc() and free() in your own .c file included in the project the linker will resolve that version.

我认为如果您在包含在项目中的自己的 .c 文件中定义 malloc() 和 free() ,链接器将解析该版本。

Now then, how do you intend to implement malloc?

那么,你打算如何实现 malloc 呢?