glibc不推荐的uu malloc_钩子功能的替代方案

glibc不推荐的uu malloc_钩子功能的替代方案,c,gcc,malloc,deprecated,glibc,C,Gcc,Malloc,Deprecated,Glibc,我正在为C编写一个内存分析器,为此我通过malloc_钩子拦截对malloc、realloc和free函数的调用。不幸的是,由于它们在多线程环境中的不良行为,它们已被弃用。我找不到一份文件来描述实现同样目标的替代最佳实践解决方案,有人能给我一些启发吗 我已经读到一个简单的#define malloc(s)malloc_hook(s)就可以了,但这不适用于我心目中的系统设置,因为它对原始代码库的干扰太大,不适合在分析/跟踪工具中使用。必须手动更改原始应用程序代码对于任何一个体面的分析器来说都是一个

我正在为C编写一个内存分析器,为此我通过malloc_钩子拦截对
malloc
realloc
free
函数的调用。不幸的是,由于它们在多线程环境中的不良行为,它们已被弃用。我找不到一份文件来描述实现同样目标的替代最佳实践解决方案,有人能给我一些启发吗

我已经读到一个简单的
#define malloc(s)malloc_hook(s)
就可以了,但这不适用于我心目中的系统设置,因为它对原始代码库的干扰太大,不适合在分析/跟踪工具中使用。必须手动更改原始应用程序代码对于任何一个体面的分析器来说都是一个杀手。最佳情况下,我正在寻找的解决方案应该通过链接到可选的共享库来启用或禁用。例如,我当前的安装程序使用一个用
\uuuuu属性((构造函数))
声明的函数来安装拦截
malloc
钩子


谢谢

您可以使用LD\U预加载和dlsym
请参见

上的“malloc和free提示”尝试了一些方法后,我终于找到了解决方法

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

void*
malloc (size_t size)
{
  [ ... ]
}
它由应用程序调用,而不是
glibc
s
malloc

现在,与
\uu malloc\u hook
的功能相当,仍然缺少一些东西

1.)呼叫者地址 除了
malloc
的原始参数外,
glibc
s
\uu malloc\u hook
s还提供调用函数的地址,这实际上是
malloc
将返回到的位置的返回地址。为了实现同样的目的,我们可以使用gcc中提供的
\u内置\u返回\u地址
函数。我没有研究过其他编译器,因为我仅限于gcc,但如果您碰巧知道如何在可移植的情况下执行此操作,请给我留言:)

我们的
malloc
函数现在如下所示:

void*
malloc (size_t size)
{
  void *caller = __builtin_return_address(0);
  [ ... ]
}
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);
}
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;
}
2.)从钩子中访问
glibc
s malloc 由于我的应用程序中仅限于glibc,因此我选择使用
\uuu libc\u malloc
来访问原始的malloc实现。或者,可以使用
dlsym(RTLD_NEXT,“malloc”)
,但该函数在第一次调用时可能会使用
calloc
,这可能会导致无限循环导致segfault

完全马洛克钩子 我的完整挂钩功能现在如下所示:

void*
malloc (size_t size)
{
  void *caller = __builtin_return_address(0);
  [ ... ]
}
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);
}
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;
}
其中
my\u malloc\u hook
如下所示:

void*
malloc (size_t size)
{
  void *caller = __builtin_return_address(0);
  [ ... ]
}
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);
}
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;
}
当然,
calloc
realloc
free
的钩子工作原理类似

动态和静态链接 有了这些功能,动态链接就可以开箱即用。链接包含malloc钩子实现的.so文件将导致应用程序对
malloc
的所有调用,以及所有通过我的钩子路由的库调用。但是静态链接是有问题的。我还没有完全理解它,但在静态链接中,malloc并不是一个弱符号,导致链接时出现多定义错误

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

下面是一个简短的例子:

gcc -o test test.c -lmalloc_hook_library -Wl,-Bstatic -l3rdparty -Wl,-Bdynamic
3rdparty
将静态链接,而
malloc_hook_库
将动态链接,从而产生预期的行为,
3rdparty
中的函数地址可通过
test
中的调试符号进行翻译。很整洁,是吗

结论 上述技术描述了一种非弃用的、相当于
\uuuu malloc\uhook
s的方法,但有几个平均限制:

\u内置呼叫方地址
仅适用于
gcc

\uuuu libc\u malloc
仅适用于
glibc

dlsym(RTLD_NEXT,[…])
是glibc中的GNU扩展

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


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

刚刚设法NDK构建了包含
\uu malloc\u hook
的代码

根据esp:


这很酷,我一定要试试。尽管需要显式地设置LD_PRELOAD让我感到困扰。而且,这似乎不适用于静态链接的二进制文件:(不幸的是,dlsym在某些情况下调用calloc。您在valgrind中使用此技术时遇到过任何问题吗?当两者结合使用时,我看到了一些奇怪的问题。@Meowskueak我没有尝试过,但valgrind往往会做一些奇怪的事情。嘿@AndreasGrapentin,我使用您的方法编写了一个通用内存堆检查器,名为更好的名字。谢谢分享!@itaych嘿,谢谢!我很高兴听到一些有用的消息:)是否已弃用?2011年glibc malloc钩子弃用被认为是有害的。钩子仍然存在:。自glibc 2.24以来,只有
\uuuuuuMalloc\u initialize\uHook
变量被标记为弃用,请检查实际人员,部分注释主页说明
t