Вывод в stderr всякий раз, когда вызывается malloc / free - PullRequest
4 голосов
/ 15 ноября 2008

В Linux / GCC / C ++ я бы хотел записывать что-то в stderr всякий раз, когда вызывается malloc / free / new / delete. Я пытаюсь понять распределение памяти в библиотеке, и поэтому я хотел бы сгенерировать этот вывод во время выполнения модульных тестов. Я использую valgrind для обнаружения утечек памяти, но я не могу найти опцию, чтобы просто регистрировать распределения.

Есть идеи? Я ищу самое простое решение. Перекомпиляция библиотеки не вариант.

Ответы [ 4 ]

15 голосов
/ 15 ноября 2008

Вы можете отслеживать звонки на malloc / free с помощью 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) +++

Для отслеживания новых / удаления вызовов без перекомпиляции вам, вероятно, потребуется использовать что-то вроде LD_PRELOAD для переопределения вызовов вашими собственными версиями, это именно то, что LeakTracer делает, что может делать то, что вы хотите.

5 голосов
/ 15 ноября 2008

В этой статье (прокрутка вниз) приводится очень четкое и краткое описание того, как переопределить глобальные операторы new и delete в C ++ (обратите внимание, что в нем нет пример для new[], но это похоже на концепцию).

Что касается переопределения malloc и free, поскольку вы работаете в Linux и с GCC, самый простой способ - использовать malloc_hook и free_hook. Здесь - очень хорошее описание того, как работают эти функции.

4 голосов
/ 14 ноября 2009

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'
<em>(the code above)</em>
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.

1 голос
/ 15 ноября 2008

Я не проверял это сам, но уверен, что это сработает:

  • Поскольку вы не хотите перекомпилировать библиотеку, для выдачи значимого результата (в отличие от только что "новый вызов для 23 байтов") может потребоваться получение трассировки стека. Я помню, как использовал функции для навигации по стеку, но сейчас не могу их найти. Возможно, вызовы system () и pstack (1) могут помочь.

  • Вы можете переопределить оператор new и delete и поместить это новое определение перед библиотекой std c ++. Это может не захватывать вызовы из контейнеров и стандартных компонентов, которые использует рассматриваемая библиотека. Это потребует повторной ссылки.

  • Использование может использовать LD_PRELOAD для изменения оператора new и динамического удаления. Это не потребует повторной ссылки, если ваше приложение динамически связано.

Надеюсь, эти указатели помогут, извините, у меня нет рецепта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...