diff options
Diffstat (limited to 'Source/lib/utils/leak_detective.c')
-rw-r--r-- | Source/lib/utils/leak_detective.c | 337 |
1 files changed, 200 insertions, 137 deletions
diff --git a/Source/lib/utils/leak_detective.c b/Source/lib/utils/leak_detective.c index 319f80513..72b14bb46 100644 --- a/Source/lib/utils/leak_detective.c +++ b/Source/lib/utils/leak_detective.c @@ -31,7 +31,7 @@ #include <dlfcn.h> #include <unistd.h> #include <syslog.h> -#define __USE_GNU +#define __USE_GNU /* needed for recursiv mutex initializer */ #include <pthread.h> #include "leak_detective.h" @@ -46,16 +46,12 @@ */ #define MEMORY_HEADER_MAGIC 0xF1367ADF -/** - * logger for the leak detective - */ -logger_t *logger; - static void install_hooks(void); static void uninstall_hooks(void); static void *malloc_hook(size_t, const void *); static void *realloc_hook(void *, size_t, const void *); static void free_hook(void*, const void *); +static void load_excluded_functions(); typedef struct memory_header_t memory_header_t; @@ -98,7 +94,7 @@ struct memory_header_t { * first mem header is just a dummy to chain * the others on it... */ -memory_header_t first_header = { +static memory_header_t first_header = { magic: MEMORY_HEADER_MAGIC, bytes: 0, stack_frame_count: 0, @@ -107,31 +103,32 @@ memory_header_t first_header = { }; /** + * logger for the leak detective + */ +static logger_t *logger; + +/** * standard hooks, used to temparily remove hooking */ -void *old_malloc_hook, *old_realloc_hook, *old_free_hook; -static bool installed = FALSE; +static void *old_malloc_hook, *old_realloc_hook, *old_free_hook; /** - * Mutex to exclusivly uninstall hooks, access heap list + * are the hooks currently installed? */ -pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static bool installed = FALSE; /** - * Setup leak detective at malloc initialization + * Mutex to exclusivly uninstall hooks, access heap list */ -void setup_leak_detective() -{ - logger = logger_manager->get_logger(logger_manager, LEAK_DETECT); - install_hooks(); -} -void (*__malloc_initialize_hook) (void) = setup_leak_detective; +static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + + /** * log stack frames queried by backtrace() * TODO: Dump symbols of static functions!!! */ -void log_stack_frames(void **stack_frames, int stack_frame_count) +static void log_stack_frames(void **stack_frames, int stack_frame_count) { char **strings; size_t i; @@ -148,9 +145,41 @@ void log_stack_frames(void **stack_frames, int stack_frame_count) } /** + * Report leaks at library destruction + */ +void report_leaks() +{ + memory_header_t *hdr; + int leaks = 0; + + /* reaquire a logger is necessary, this will force ((destructor)) + * order to work correctly */ + logger = logger_manager->get_logger(logger_manager, LEAK_DETECT); + for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) + { + logger->log(logger, ERROR, "Leak (%d bytes at %p)", hdr->bytes, hdr + 1); + log_stack_frames(hdr->stack_frames, hdr->stack_frame_count); + leaks++; + } + + switch (leaks) + { + case 0: + logger->log(logger, CONTROL, "No leaks detected"); + break; + case 1: + logger->log(logger, ERROR, "One leak detected"); + break; + default: + logger->log(logger, ERROR, "%d leaks detected", leaks); + break; + } +} + +/** * Installs the malloc hooks, enables leak detection */ -void install_hooks() +static void install_hooks() { if (!installed) { @@ -167,7 +196,7 @@ void install_hooks() /** * Uninstalls the malloc hooks, disables leak detection */ -void uninstall_hooks() +static void uninstall_hooks() { if (installed) { @@ -181,7 +210,7 @@ void uninstall_hooks() /** * Hook function for malloc() */ -static void *malloc_hook(size_t bytes, const void *caller) +void *malloc_hook(size_t bytes, const void *caller) { memory_header_t *hdr; @@ -209,7 +238,7 @@ static void *malloc_hook(size_t bytes, const void *caller) /** * Hook function for free() */ -static void free_hook(void *ptr, const void *caller) +void free_hook(void *ptr, const void *caller) { void *stack_frames[STACK_FRAMES_COUNT]; int stack_frame_count; @@ -225,12 +254,11 @@ static void free_hook(void *ptr, const void *caller) if (hdr->magic != MEMORY_HEADER_MAGIC) { pthread_mutex_unlock(&mutex); - /* TODO: Since we get a lot of theses from the pthread lib, its deactivated for now... */ + /* TODO: since pthread_join cannot be excluded cleanly, we are not whining about bad frees */ return; logger->log(logger, ERROR, "freeing of invalid memory (%p)", ptr); stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); log_stack_frames(stack_frames, stack_frame_count); - kill(getpid(), SIGKILL); return; } /* remove magic from hdr */ @@ -252,7 +280,7 @@ static void free_hook(void *ptr, const void *caller) /** * Hook function for realloc() */ -static void *realloc_hook(void *old, size_t bytes, const void *caller) +void *realloc_hook(void *old, size_t bytes, const void *caller) { void *new; memory_header_t *hdr = old - sizeof(memory_header_t); @@ -281,146 +309,198 @@ static void *realloc_hook(void *old, size_t bytes, const void *caller) return new; } + /** - * Report leaks at library destruction + * Setup leak detective */ -void __attribute__ ((destructor)) report_leaks() +void leak_detective_init() { - memory_header_t *hdr; - int leaks = 0; - - /* reaquire a logger is necessary, this will force ((destructor)) - * order to work correctly */ logger = logger_manager->get_logger(logger_manager, LEAK_DETECT); - - for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) - { - logger->log(logger, ERROR, "Leak (%d bytes at %p)", hdr->bytes, hdr + 1); - log_stack_frames(hdr->stack_frames, hdr->stack_frame_count); - leaks++; - } - - switch (leaks) - { - case 0: - logger->log(logger, CONTROL, "No leaks detected"); - break; - case 1: - logger->log(logger, ERROR, "One leak detected"); - break; - default: - logger->log(logger, ERROR, "%d leaks detected", leaks); - break; - } + load_excluded_functions(); + install_hooks(); } -/* +/** + * Clean up leak detective + */ +void leak_detective_cleanup() +{ + report_leaks(); + uninstall_hooks(); +} + + +/** * The following glibc functions are excluded from leak detection, since * they use static allocated buffers or other ugly allocation hacks. - * The Makefile links theses function preferred to their counterparts - * in the target lib... - * TODO: Generic handling would be nice, with a list of blacklisted - * functions. + * For this to work, the linker must link libstrongswan preferred to + * the other (overriden) libs. */ +struct excluded_function { + char *lib_name; + char *function_name; + void *handle; + void *lib_function; +} excluded_functions[] = { + {"libc.so.6", "inet_ntoa", NULL, NULL}, + {"libpthread.so.0", "pthread_create", NULL, NULL}, + {"libpthread.so.0", "pthread_cancel", NULL, NULL}, + {"libpthread.so.0", "pthread_join", NULL, NULL}, + {"libpthread.so.0", "_pthread_cleanup_push",NULL, NULL}, + {"libpthread.so.0", "_pthread_cleanup_pop", NULL, NULL}, + {"libc.so.6", "mktime", NULL, NULL}, + {"libc.so.6", "vsyslog", NULL, NULL}, +}; +#define INET_NTOA 0 +#define PTHREAD_CREATE 1 +#define PTHREAD_CANCEL 2 +#define PTHREAD_JOIN 3 +#define PTHREAD_CLEANUP_PUSH 4 +#define PTHREAD_CLEANUP_POP 5 +#define MKTIME 6 +#define VSYSLOG 7 +/** + * Load libraries and function pointers for excluded functions + */ +static void load_excluded_functions() +{ + int i; + + for (i = 0; i < sizeof(excluded_functions)/sizeof(struct excluded_function); i++) + { + void *handle, *function; + handle = dlopen(excluded_functions[i].lib_name, RTLD_LAZY); + if (handle == NULL) + { + kill(getpid(), SIGSEGV); + } + + function = dlsym(handle, excluded_functions[i].function_name); + + if (function == NULL) + { + dlclose(handle); + kill(getpid(), SIGSEGV); + } + excluded_functions[i].handle = handle; + excluded_functions[i].lib_function = function; + } +} + char *inet_ntoa(struct in_addr in) { - char *(*_inet_ntoa)(struct in_addr); - void *handle; + char *(*_inet_ntoa)(struct in_addr) = excluded_functions[INET_NTOA].lib_function; char *result; pthread_mutex_lock(&mutex); uninstall_hooks(); - handle = dlopen("libc.so.6", RTLD_LAZY); - if (handle == NULL) - { - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } - _inet_ntoa = dlsym(handle, "inet_ntoa"); - - if (_inet_ntoa == NULL) - { - dlclose(handle); - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } result = _inet_ntoa(in); - dlclose(handle); + install_hooks(); pthread_mutex_unlock(&mutex); return result; } - int pthread_create(pthread_t *__restrict __threadp, __const pthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), void *__restrict __arg) { int (*_pthread_create) (pthread_t *__restrict __threadp, __const pthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), - void *__restrict __arg); - void *handle; + void *__restrict __arg) = excluded_functions[PTHREAD_CREATE].lib_function; int result; pthread_mutex_lock(&mutex); uninstall_hooks(); - handle = dlopen("libpthread.so.0", RTLD_LAZY); - if (handle == NULL) - { - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } - _pthread_create = dlsym(handle, "pthread_create"); - - if (_pthread_create == NULL) - { - dlclose(handle); - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } result = _pthread_create(__threadp, __attr, __start_routine, __arg); - dlclose(handle); + install_hooks(); pthread_mutex_unlock(&mutex); return result; } -time_t mktime(struct tm *tm) +int pthread_cancel(pthread_t __th) { - time_t (*_mktime)(struct tm *tm); - time_t result; - void *handle; + int (*_pthread_cancel) (pthread_t) = excluded_functions[PTHREAD_CANCEL].lib_function; + int result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _pthread_cancel(__th); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} +/* TODO: join has probs, since it dellocates memory + * allocated (somewhere) with leak_detective :-(. + * We should exclude all pthread_ functions to fix it !? +int pthread_join(pthread_t __th, void **__thread_return) +{ + int (*_pthread_join) (pthread_t, void **) = excluded_functions[PTHREAD_JOIN].lib_function; + int result; + pthread_mutex_lock(&mutex); uninstall_hooks(); + + result = _pthread_join(__th, __thread_return); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} - handle = dlopen("libc.so.6", RTLD_LAZY); - if (handle == NULL) - { - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } - _mktime = dlsym(handle, "mktime"); +void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) +{ + int (*__pthread_cleanup_push) (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) = + excluded_functions[PTHREAD_CLEANUP_PUSH].lib_function; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + __pthread_cleanup_push(__buffer, __routine, __arg); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return; +} + +void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, int __execute) +{ + int (*__pthread_cleanup_pop) (struct _pthread_cleanup_buffer *__buffer, int __execute) = + excluded_functions[PTHREAD_CLEANUP_POP].lib_function; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + __pthread_cleanup_pop(__buffer, __execute); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return; +}*/ - if (_mktime == NULL) - { - dlclose(handle); - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } +time_t mktime(struct tm *tm) +{ + time_t (*_mktime)(struct tm *tm) = excluded_functions[MKTIME].lib_function; + time_t result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + result = _mktime(tm); - dlclose(handle); + install_hooks(); pthread_mutex_unlock(&mutex); return result; @@ -428,30 +508,13 @@ time_t mktime(struct tm *tm) void vsyslog (int __pri, __const char *__fmt, __gnuc_va_list __ap) { - void (*_vsyslog) (int __pri, __const char *__fmt, __gnuc_va_list __ap); - void *handle; + void (*_vsyslog) (int __pri, __const char *__fmt, __gnuc_va_list __ap) = excluded_functions[VSYSLOG].lib_function; pthread_mutex_lock(&mutex); uninstall_hooks(); - - handle = dlopen("libc.so.6", RTLD_LAZY); - if (handle == NULL) - { - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } - _vsyslog = dlsym(handle, "vsyslog"); - - if (_vsyslog == NULL) - { - dlclose(handle); - install_hooks(); - pthread_mutex_unlock(&mutex); - kill(getpid(), SIGSEGV); - } + _vsyslog(__pri, __fmt, __ap); - dlclose(handle); + install_hooks(); pthread_mutex_unlock(&mutex); return; |