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

发布于 2024-07-09 03:37:36 字数 194 浏览 8 评论 0原文

对于 Linux/GCC/C++,我想在调用 malloc/free/new/delete 时向 stderr 记录一些内容。 我试图了解库的内存分配,因此我想在运行单元测试时生成此输出。 我使用 valgrind 进行内存泄漏检测,但我找不到使其仅记录分配的选项。

有任何想法吗? 我正在寻找最简单的解决方案。 重新编译库不是一个选项。

With Linux/GCC/C++, I'd like to record something to stderr whenever malloc/free/new/delete are called. I'm trying to understand a library's memory allocations, and so I'd like to generate this output while I'm running unit tests. I use valgrind for mem leak detection, but I can't find an option to make it just log allocations.

Any ideas? I'm looking for the simplest possible solution. Recompiling the library is not an option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

晒暮凉 2024-07-16 03:37:36

您可以使用 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 可以实现您想要的功能。

You can trace calls to malloc/free with ltrace:

#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) +++

To trace new/delete calls without recompiling you will probably need to use something like LD_PRELOAD to override the calls with your own versions, this is precisely what LeakTracer does which might do what you want.

不回头走下去 2024-07-16 03:37:36

本文(向下滚动到底部)提供关于如何在 C++ 中重写全局 newdelete 运算符的非常清晰简洁的描述(请注意,它没有提供 new[]< /code>,但概念相似)。

至于覆盖 malloc 和 free,由于您使用的是 Linux 和 GCC,最简单的方法是使用 malloc_hookfree_hook这里很好地描述了这些函数的工作原理。

This article (scroll down to the bottom) provides a very clear and concise description of how to override the global new and delete operators in C++ (note that it doesn't provide an example for new[], but it's similar in concept).

As far as overriding malloc and free, since you're working on Linux and with GCC, the easiest method is to use malloc_hook and free_hook. Here is a very good description of how these functions work.

世界如花海般美丽 2024-07-16 03:37:36

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 ,请小心这一点。

malloc_hook(3) allows you to globally interpose your own malloc function. (There's __realloc_hook __free_hook etc. as well, I've just left them out for simplicity.)

#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 might call malloc, which is why we undo the hook temporarily. Be careful of this if when you hook malloc in any way.

琉璃梦幻 2024-07-16 03:37:36

我自己没有测试过这个,但我很确定这些会起作用:

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

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

  • 使用可以使用LD_PRELOAD来动态改变operator new和delete。 如果您的应用程序是动态链接的,则不需要重新链接。

希望这些建议有所帮助,很抱歉我没有食谱。

I have not tested this myself, but I am pretty sure these would work:

  • Since you do not want to re-compile the library, giving meaningful output (vs. just "new called for 23 bytes") may require getting a stack trace. I remember using functions to navigate the stack, but I cannot find them right now. Maybe a call to system() and pstack(1) can do the trick.

  • You can re-define operator new and delete, and put this new definition ahead of the std c++ library. This may not capture the calls from containers and standard components that the library in question is using. This would require a relink.

  • Use can use LD_PRELOAD to change operator new and delete dynamically. This would not require a re-link if your application is dynamically linked.

Hope these pointers help, I am sorry I do not have a recipe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文