glibc弃用的__malloc_hook功能的替代方案

时间:2013-07-23 07:02:34

标签: c gcc malloc deprecated glibc

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

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

由于

3 个答案:

答案 0 :(得分:44)

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

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

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

应用程序而不是glibc s malloc调用哪个。

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

1。)来电地址

malloc的原始参数外,glibc s __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 hook

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

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的钩子的工作方式相似。

动态和静态链接

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

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

这是一个简短的例子:

malloc

gcc -o test test.c -lmalloc_hook_library -Wl,-Bstatic -l3rdparty -Wl,-Bdynamic 将静态链接,而3rdparty将动态链接,导致预期的行为,malloc_hook_library中的函数地址可通过{{1}中的调试符号进行翻译}}。很整洁,呵呵?

Conlusion

上述技术描述了3rdparty的一种非弃用的,非常等效的方法,但有一些平均限制:

test仅适用于__malloc_hook

__builtin_caller_address仅适用于gcc

__libc_mallocglibc

中的GNU扩展程序

链接器标志dlsym(RTLD_NEXT, [...])glibc特定于GNU binutils。

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

答案 1 :(得分:2)

您可以使用LD_PRELOAD&对dlsym 请参阅http://www.slideshare.net/tetsu.koba/presentations

上的“malloc和免费提示”

答案 2 :(得分:0)

只需设法NDK构建包含__malloc_hook的代码。

根据https://android.googlesource.com/platform/bionic/+/master/libc/include/malloc.h,尤其是,它似乎已在Android API v28中恢复了。

extern void* (*volatile __malloc_hook)(size_t __byte_count, const void* __caller) __INTRODUCED_IN(28);