每当调用malloc / free时输出到stderr

时间:2008-11-15 03:38:17

标签: c++ linux memory malloc valgrind

使用Linux / GCC / C ++,我想在调用malloc / free / new / delete时向stderr记录一些东西。我正在尝试理解库的内存分配,因此我想在运行单元测试时生成此输出。我使用valgrind进行内存泄漏检测,但我找不到一个选项来使它只是日志分配。

有什么想法吗?我正在寻找最简单的解决方案。不能重新编译库。

4 个答案:

答案 0 :(得分:15)

您可以使用ltrace跟踪对malloc / free的调用:

#include <stdlib.h>

int main (void)
{
  void *ptr = malloc(10);
  free(ptr);

  return 0;
}


$ g++ test.cpp -o test
$ ltrace -e malloc,free ./test
malloc(10)                                       = 0x804a008
free(0x804a008)                                  = <void>
+++ exited (status 0) +++

要跟踪新的/删除调用而不重新编译,您可能需要使用类似LD_PRELOAD的内容来覆盖使用您自己的版本的调用,这正是LeakTracer可以执行您想要的操作。

答案 1 :(得分:5)

This article(向下滚动到底部)提供了如何在C ++中覆盖全局newdelete运算符的非常简洁明了的说明(请注意,它不提供new[]的示例,但它在概念上类似。)

至于重写malloc和free,因为你在Linux和GCC上工作,最简单的方法是使用malloc_hookfree_hookHere是对这些功能如何运作的非常好的描述。

答案 2 :(得分:4)

malloc_hook(3)允许您全局设置自己的malloc功能。 (还有__realloc_hook __free_hook等等,我只是为了简单起见而将它们排除在外。)

#include <stdio.h>
#include <malloc.h>

static void *(*old_malloc_hook)(size_t, const void *);

static void *new_malloc_hook(size_t size, const void *caller) {
    void *mem;

    __malloc_hook = old_malloc_hook;
    mem = malloc(size);
    fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
    __malloc_hook = new_malloc_hook;

    return mem;
}

static void init_my_hooks(void) {
    old_malloc_hook = __malloc_hook;
    __malloc_hook = new_malloc_hook;
}

void (*__malloc_initialize_hook)(void) = init_my_hooks;
$ cat >mem.c <<'EOF'
(the code above)
EOF
$ cc -fPIC -shared -o mem.so mem.c
$ LD_PRELOAD=./mem.so ls
0x7ffc14931adc: malloc(5) = 0xb40010
0x7ffc1492c6b0: malloc(120) = 0xb40030
0x7ffc1497f61a: malloc(12) = 0xb40010
0x7ffc1492be38: malloc(776) = 0xb400b0
…

printf可能会调用malloc,这就是我们暂时撤消挂钩的原因。如果以任何方式挂钩malloc,请注意这一点。

答案 3 :(得分:1)

我自己没有对此进行测试,但我确信这些可行:

  • 由于您不想重新编译库,因此提供有意义的输出(而不仅仅是“新调用23字节”)可能需要获取堆栈跟踪。我记得使用函数来导航堆栈,但我现在找不到它们。也许调用system()和pstack(1)可以解决问题。

  • 您可以重新定义operator new和delete,并将此新定义放在std c ++库之前。这可能无法捕获有问题的库正在使用的容器和标准组件的调用。这需要重新链接。

  • 使用可以使用LD_PRELOAD更改operator new并动态删除。如果您的应用程序是动态链接的,则不需要重新链接。

希望这些指针有所帮助,对不起,我没有食谱。