- library initialization done at a central point (library.c)
authorMartin Willi <martin@strongswan.org>
Thu, 20 Apr 2006 11:48:57 +0000 (11:48 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 20 Apr 2006 11:48:57 +0000 (11:48 -0000)
- some leak_detective fixes

Source/Makefile
Source/lib/Makefile.lib
Source/lib/library.c [new file with mode: 0644]
Source/lib/utils/leak_detective.c
Source/lib/utils/leak_detective.h
Source/lib/utils/logger_manager.c
Source/lib/utils/logger_manager.h

index 9d51ea9..7991257 100644 (file)
@@ -27,9 +27,8 @@ BINNAMELIB=  $(BUILD_DIR)libstrongswan.so
 
 MAIN_DIR= ./
 
-LDFLAGS= -ldl -lgmp -lpthread -rdynamic
-
-CFLAGS= -Icharon -Ilib -Istroke -Wall -g -fPIC -DLEAK_DETECTIVE
+CFLAGS= -Icharon -Ilib -Istroke -fPIC -Wall -g -DLEAK_DETECTIVE
+# CFLAGS= -Icharon -Ilib -Istroke -fPIC -O3
 
 # objects is extended by each included Makefile
 CHARON_OBJS=
@@ -58,10 +57,10 @@ build_dir:
                                                        mkdir -p $(BUILD_DIR)
                                                        
 $(BINNAMELIB) :                                build_dir $(LIB_OBJS)
-                                                       $(CC) -shared $(LIB_OBJS) -o $@
+                                                       $(CC) -ldl -lgmp -lpthread -shared $(LIB_OBJS) -o $@
 
 $(BINNAMECHARON) :                     build_dir $(CHARON_OBJS) $(BINNAMELIB) $(BUILD_DIR)daemon.o
-                                                       $(CC) -ldl -lgmp -rdynamic -L./bin -lstrongswan -lpthread $(CHARON_OBJS) $(BUILD_DIR)daemon.o -o $@
+                                                       $(CC) -L./bin -lstrongswan $(CHARON_OBJS) $(BUILD_DIR)daemon.o -o $@
 
 $(BINNAMETEST) :                       build_dir $(CHARON_OBJS) $(TEST_OBJS) $(BINNAMELIB) $(BUILD_DIR)testcases.o
                                                        $(CC) -L./bin -lstrongswan  $(LDFLAGS) $(CHARON_OBJS) $(TEST_OBJS) $(BUILD_DIR)testcases.o -o $@
index 389a31b..f18ea2d 100644 (file)
@@ -22,6 +22,10 @@ LIB_OBJS+= $(BUILD_DIR)definitions.o
 $(BUILD_DIR)definitions.o :            $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h
                                                                $(CC) $(CFLAGS) -c -o $@ $<
 
+LIB_OBJS+= $(BUILD_DIR)library.o
+$(BUILD_DIR)library.o :                        $(LIB_DIR)library.c
+                                                               $(CC) $(CFLAGS) -c -o $@ $<
+
 include $(MAIN_DIR)lib/crypto/Makefile.transforms
 include $(MAIN_DIR)lib/utils/Makefile.utils
 include $(MAIN_DIR)lib/asn1/Makefile.asn1
diff --git a/Source/lib/library.c b/Source/lib/library.c
new file mode 100644 (file)
index 0000000..fa9c732
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * @file library.c
+ * 
+ * @brief Library (de-)initialization.
+ * 
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <utils/logger_manager.h>
+#include <utils/leak_detective.h>
+
+/**
+ * Called whenever the library is linked from a process
+ */
+void __attribute__ ((constructor)) library_init()
+{
+       logger_manager_init();
+       leak_detective_init();  
+}
+
+/**
+ * Called whenever the library is unlinked from a process
+ */
+void __attribute__ ((destructor)) library_cleanup()
+{
+       leak_detective_cleanup();
+       logger_manager_cleanup();
+}
index 319f805..72b14bb 100644 (file)
@@ -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"
  */
 #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;
index 1b0b222..13c0d01 100644 (file)
  */
 #define STACK_FRAMES_COUNT 30
 
+/**
+ * Initialize leak detective, activates it
+ */
+void leak_detective_init();
+
+/**
+ * Cleanup leak detective, deactivates it
+ */
+void leak_detective_cleanup();
 
+#else /* !LEAK_DETECTIVE */
 
+#define leak_detective_init() {}
+#define leak_detective_cleanup() {}
 
 #endif /* LEAK_DETECTIVE */
 
index de92d0a..ecbe1a6 100644 (file)
@@ -187,7 +187,7 @@ static void set_output(private_logger_manager_t *this, logger_context_t context,
 /**
  * Creates the instance of the logger manager at library startup
  */
-void __attribute__ ((constructor)) logger_manager_create()
+void logger_manager_init()
 {
        int i;
        
@@ -210,7 +210,7 @@ void __attribute__ ((constructor)) logger_manager_create()
 /**
  * Destroy the logger manager at library exit
  */
-void __attribute__ ((destructor)) logger_manager_destroy()
+void logger_manager_cleanup()
 {
        int i;
        for (i = 0; i < LOGGER_CONTEXT_ROOF; i++)
index 074dd74..3cfba73 100644 (file)
@@ -78,6 +78,7 @@ typedef struct logger_manager_t logger_manager_t;
  * 
  * @b Constructors:
  *  - none, logger_manager is the single instance
+ *    use logger_manager_init/logger_manager_cleanup
  * 
  * @see logger_t
  * 
@@ -144,4 +145,8 @@ struct logger_manager_t {
  */
 extern logger_manager_t *logger_manager;
 
+void logger_manager_init();
+
+void logger_manager_cleanup();
+
 #endif /*LOGGER_MANAGER_H_*/