glibc弃用的__malloc_hookfunction的替代方案

我正在为C编写一个内存分析器,因为它通过malloc_hooks拦截对mallocreallocfree函数的调用。 不幸的是,由于它们在multithreading环境中的不良行为而被弃用。 我找不到描述替代最佳实践解决方案的文档来实现同样的事情,有人可以启发我吗?

我已经读过一个简单的#define malloc(s) malloc_hook(s)可以解决这个问题,但是这对我想到的系统设置不起作用,因为它太过于干扰原始代码库而不适合用于分析/跟踪工具。 必须手动更改原始应用程序代码是任何体面的分析器的杀手。 最理想的是,我正在寻找的解决方案应该通过链接到可选的共享库来启用或禁用。 例如,我当前的设置使用用__attribute__ ((constructor))函数)声明的函数来安装拦截malloc挂钩。

谢谢

在尝试了一些事情后,我终于设法弄清楚如何做到这一点。

首先,在glibcmalloc被定义为弱符号,这意味着它可以被应用程序或共享库覆盖。 因此,不一定需要LD_PRELOAD 。 相反,我在共享库中实现了以下function:

 void* malloc (size_t size) { [ ... ] } 

应用程序调用它而不是glibcmalloc

现在,为了等同于__malloc_hook的function,仍然缺少一些东西。

1.)来电者地址

除了malloc的原始参数之外, glibc__malloc_hook还提供了调用函数的地址,它实际上是malloc返回的返回地址。 为了实现同样的目的,我们可以使用gcc中提供的__builtin_return_address函数。 我没有看过其他的编译器,因为我无论如何都只限于gcc,但是如果你碰巧知道怎么做这样的东西,请给我留言:)

我们的malloc函数现在看起来像这样:

 void* malloc (size_t size) { void *caller = __builtin_return_address(0); [ ... ] } 

2.)从你的钩子中访问glibc的malloc

因为我在我的应用程序中仅限于glibc,所以我选择使用__libc_malloc来访问原始的malloc实现。 或者,可以使用dlsym(RTLD_NEXT, "malloc") ,但是可能存在这个函数在第一次调用时使用calloc缺陷,可能导致无限循环导致段错误。

完整的malloc钩子

我完整的挂钩function现在看起来像这样:

 extern void *__libc_malloc(size_t size); int malloc_hook_active = 0; void* malloc (size_t size) { void *caller = __builtin_return_address(0); if (malloc_hook_active) return my_malloc_hook(size, caller); return __libc_malloc(size); } 

my_malloc_hook看起来像这样:

 void* my_malloc_hook (size_t size, void *caller) { void *result; // deactivate hooks for logging malloc_hook_active = 0; result = malloc(size); // do logging [ ... ] // reactivate hooks malloc_hook_active = 1; return result; } 

当然, callocreallocfree work的钩子类似。

动态和静态链接

使用这些function,动态链接开箱即用。 链接包含malloc钩子实现的.so文件将导致从应用程序中调用malloc ,并且所有库调用都将通过我的钩子进行路由。 但静态链接存在问题。 我还没有完全绕过它,但在静态链接中malloc不是一个弱符号,导致链接时出现多重定义错误。

如果由于某种原因需要静态链接,例如将第三方库中的函数地址通过调试符号转换为代码行,则可以静态链接这些第三方库,同时仍动态链接malloc挂钩,避免多重定义问题。 我还没有找到一个更好的解决方法,如果你知道一个,请随时给我留言。

这是一个简短的例子:

 gcc -o test test.c -lmalloc_hook_library -Wl,-Bstatic -l3rdparty -Wl,-Bdynamic 

malloc_hook_library将静态链接,而malloc_hook_library将动态链接,从而产生预期的行为,并且malloc_hook_library的函数地址可通过test调试符号进行翻译。 挺整洁的,对吧?

Conlusion

上面的技术描述了一种非弃用的,几乎与__malloc_hook相同的方法,但有一些平均限制:

__builtin_caller_address仅适用于gcc

__libc_malloc仅适用于glibc

dlsym(RTLD_NEXT, [...])glibc的GNU扩展

链接器标志-Wl,-Bstatic-Wl,-Bdynamic特定于GNU binutils。

换句话说,这个解决方案是完全不可移植的,如果将钩子库移植到非GNU操作系统,则必须添加替代解决方案。

您可以使用LD_PRELOAD和dlsym请参阅http://www.slideshare.net/tetsu.koba/presentations上的 “malloc和免费提示” 。