Для приложения c ++ arm мне нужно отслеживать распределение памяти. Для этого я использую хуки памяти gcc. Пока я печатаю распределения и освобождения, см. Код ниже.
Однако malloc
и free
не складываются. Иногда я вижу free
в блоке памяти, который проходил раньше, не перехватывал malloc раньше. Или память освобождается дважды. Конечно, это может быть ошибка в моем коде, хотя я не получаю segfault. Но я также вижу, что malloc
иногда возвращает указатель, который он возвращал раньше, и в то же время не было free
(по крайней мере, мой бесплатный хук не был вызван).
Так что я предполагаю, что некоторые malloc
и free'
не передаются через мои хуки. Обратите внимание, что, когда я отслеживаю только распределение c ++, все складывается хорошо.
У кого-нибудь есть идеи?
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <new>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static void push_memhooks();
static void pop_memhooks();
static void *malloc_hook(size_t size, const void *ret)
{
pthread_mutex_lock(&lock);
pop_memhooks();
void *mem = malloc(size);
if (mem) {
printf("malloc %p\n", mem);
}
push_memhooks();
pthread_mutex_unlock(&lock);
return mem;
}
static void *realloc_hook(void* ptr, size_t size, const void *ret)
{
pthread_mutex_lock(&lock);
pop_memhooks();
void* mem = realloc(ptr, size);
if (mem) {
printf("realloc %p -> %p\n", ptr, mem);
}
push_memhooks();
pthread_mutex_unlock(&lock);
return mem;
}
static void* memalign_hook(size_t boundary, size_t size, const void *ret)
{
pthread_mutex_lock(&lock);
pop_memhooks();
void* mem = memalign(boundary, size);
if (mem) {
printf("memalign %p\n", mem);
}
push_memhooks();
pthread_mutex_unlock(&lock);
return mem;
}
static void free_hook(void *mem, const void *ret)
{
pthread_mutex_lock(&lock);
pop_memhooks();
free(mem);
printf("free %p\n", mem);
push_memhooks();
pthread_mutex_unlock(&lock);
}
void *operator new(size_t size)
{
void* mem = malloc(size);
if (!mem) {
throw std::bad_alloc();
}
return mem;
}
void operator delete(void* mem)
{
free(mem);
}
void *operator new[](size_t size)
{
void* mem = malloc(size);
if (!mem) {
throw std::bad_alloc();
}
return mem;
}
void operator delete[](void* mem)
{
free(mem);
}
static int memhooks = 0;
static void push_memhooks()
{
if (++memhooks == 1) {
__malloc_hook = malloc_hook;
__realloc_hook = realloc_hook;
__free_hook = free_hook;
__memalign_hook = memalign_hook;
}
}
static void pop_memhooks()
{
if (--memhooks == 0) {
__malloc_hook = NULL;
__realloc_hook = NULL;
__free_hook = NULL;
__memalign_hook = NULL;
}
}
static void install_memhooks ()
{
push_memhooks();
}
void (*__malloc_initialize_hook)(void) = install_memhooks;
Например, я получаю следующий вывод, когда извлекаю трассировку для указателя, который показывает странное поведение.
<snip>
malloc 0x8234818
free 0x8234818
malloc 0x8234818
malloc 0x8234818
free 0x8234818
<snip>
Обратите внимание на два последовательных malloc.
Решение : Как упоминал Крис в своем ответе, в приведенном выше коде есть условие гонки. К сожалению, перехватчики malloc не могут безопасно использоваться в многопоточной среде при удалении и переустановке перехватчиков, как я. По той же причине mcheck нельзя использовать в многопоточных приложениях (http://sources.redhat.com/bugzilla/show_bug.cgi?id=9939).
Реализация malloc
/ realloc
/ free
и вызов версий libc с использованием dlsym(RTLD_NEXT, "malloc")
также не работали. Во-первых, dlsym
вызывает calloc
, поэтому для предотвращения бесконечной рекурсии здесь требуется особая осторожность. Во-вторых, при вызове libc malloc
процесс зависает. Кроме того, я вижу, что мой __malloc_initialize_hook
не вызывается. Поэтому я предполагаю, что, предоставляя мою собственную malloc
реализацию, libc malloc
не инициализируется должным образом.
Мое текущее решение имеет встроенную реализацию dlmalloc для удаления зависимости от malloc libc. Теперь мне не нужно постоянно удалять / переустанавливать крючки malloc. Я устанавливаю ловушки один раз, и мои ловушки распределяют память, используя dlmalloc.