c - Are the gcc memory hooks sometimes bypassed? -
for c++ arm application need trace memory allocations. using gcc memory hooks. printing allocations , deallocations, see code below.
however, malloc
's , free
's don't add up. see free
on memory block pass through didn't malloc hook before. or memory freed twice. of course bug in code,although don't segfault. see malloc
returns pointer has returned before , there has been no free
in meantime (at least free hook wasn't called).
so guess malloc
's , free'
s not passed through hooks. note when trace c++ allocations things add nicely.
does have ideas?
#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;
for example, following output when grep trace pointer shows strange behaviour.
<snip> malloc 0x8234818 free 0x8234818 malloc 0x8234818 malloc 0x8234818 free 0x8234818 <snip>
notice 2 consecutive malloc's.
solution: chris mentioned in answer, there's race condition in code above. unfortunately, malloc hooks cannot safely used in multithreaded environment when removing , reinstalling hooks way do. same reason, mcheck cannot used in multithreaded apps (http://sources.redhat.com/bugzilla/show_bug.cgi?id=9939).
implementing malloc
/realloc
/free
, calling libc versions using dlsym(rtld_next, "malloc")
didn't work either. first, dlsym
calls calloc
, special care needed prevent infinite recursion here. second, when calling libc malloc
, process hangs. furthermore, see __malloc_initialize_hook
doesn't called. guess providing own malloc
implementation, libc malloc
isn't initialized.
my current solution has dlmalloc implementation embedded remove dependency on libc malloc. don't have continuously remove/reinstall malloc hooks. install hooks once , hooks allocate memory using dlmalloc.
if you're running in multithreaded environment, have race condition might cause miss calls malloc/free. when malloc_hook function called, unhooks hooks, calls malloc , rehooks hooks. if other thread calls malloc/free while hooks unhooked, won't see call. mutex doesn't help, while unhooked, malloc/free call won't call hook function, won't wait on mutex.
edit
my preferred way of hooking/intecepting malloc in program intercept calls program using macros, without worrying calls within stdlib. create wrap_malloc file with:
#define malloc(sz) wrap_malloc(sz, __file__, __line__) #define free(p) wrap_free(p, __file__, __line__) #define realloc(p, sz) wrap_realloc(p, sz, __file__, __line__) #define calloc(s1, s2) wrap_calloc(s1, s2, __file__, __line__)
then compile code -imacros wrap_malloc
. file defines wrap_malloc , friends needs appropriate #undef
s, no other changes code needed.
Comments
Post a Comment