【问题标题】:how can i override malloc(), calloc(), free() etc under OS X?我如何在 OS X 下覆盖 malloc()、calloc()、free() 等?
【发布时间】:2010-10-30 02:47:42
【问题描述】:

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

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

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

【问题讨论】:

标签: xcode macos malloc overriding


【解决方案1】:

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

第一步是使用这样的代码创建一个库,然后使用常规共享库链接选项 (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);
}

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

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

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

有关动态链接器环境变量的更多信息,请参阅the dyld manual page

这个方法很通用。但是有一些限制:

  • 您将无法转移直接系统调用
  • 如果应用程序本身欺骗您使用dlsym() 加载malloc 的地址,呼叫将不会被转移。但是,除非您还通过转移dlsym 来欺骗它!

【讨论】:

    【解决方案2】:

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

    【讨论】:

    【解决方案3】:

    经过大量搜索(包括这里)和 10.7 的问题,我决定写一篇关于这个主题的博客文章:How to set malloc hooks in OSX Lion

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

    基本解决方案:

    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
    }
    

    【讨论】:

      【解决方案4】:

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

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

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

      示例

      #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);
      }
      

      建筑

      $ 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
      

      希望这对将来的其他人有所帮助!

      【讨论】:

        【解决方案5】:

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

        void* _mymalloc(size_t size)
        {
            void* ptr = malloc(size);
        
            /* do your stat work? */
        
            return ptr;
        }

        #define malloc(sz_) _mymalloc(sz_)

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

        【讨论】:

        • 这不适用于 C++ 运算符 new/delete 或没有源代码的库
        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

          查看 Emery Berger(Hoard 内存分配器的作者)在 OSX 上替换分配器的方法https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp(以及一些其他文件,您可以通过遵循包含来跟踪自己)。

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

          【讨论】:

          • 注册一个新的默认区域是可行的,但如果你只需要一些“基本统计数据”,有时就太过分了,就像问题所表明的那样。挂钩到默认区域更容易,但它不再像亚历克斯所描述的那样工作,那么为什么在没有任何评论的情况下投票否决只能帮助解决问题的答案?
          猜你喜欢
          • 2018-05-01
          • 2011-05-05
          • 2020-03-26
          • 1970-01-01
          • 2018-06-12
          • 2012-03-02
          • 1970-01-01
          • 2016-02-04
          • 1970-01-01
          相关资源
          最近更新 更多