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

And*_*tin 33 c malloc gcc glibc deprecated

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

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

谢谢

And*_*tin 50

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

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

void*
malloc (size_t size)
{
  [ ... ]
}
Run Code Online (Sandbox Code Playgroud)

哪个被应用程序调用而不是glibcs malloc.

现在,为了相当于__malloc_hooks功能,仍然缺少一些东西.

1.)来电者地址

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

我们的malloc功能现在看起来像这样:

void*
malloc (size_t size)
{
  void *caller = __builtin_return_address(0);
  [ ... ]
}
Run Code Online (Sandbox Code Playgroud)

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

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

完整的malloc钩子

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

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);
}
Run Code Online (Sandbox Code Playgroud)

这里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;
}
Run Code Online (Sandbox Code Playgroud)

当然,挂钩calloc,reallocfree类似的工作.

动态和静态链接

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

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

这是一个简短的例子:

gcc -o test test.c -lmalloc_hook_library -Wl,-Bstatic -l3rdparty -Wl,-Bdynamic
Run Code Online (Sandbox Code Playgroud)

3rdparty将静态链接,同时malloc_hook_library将动态链接,导致预期的行为,以及3rdparty可通过调试符号转换的函数地址test.挺整洁的,对吧?

Conlusion

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

__builtin_caller_address 只适用于 gcc

__libc_malloc 只适用于 glibc

dlsym(RTLD_NEXT, [...]) 是一个GNU扩展 glibc

链接器标志-Wl,-Bstatic并且-Wl,-Bdynamic特定于GNU binutils.

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