From c3af5ccdbc22e8990d04ec2f89ad1f2e053655e9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 24 Mar 2003 03:16:58 +0000 Subject: 2003-03-23 Havoc Pennington * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with DBUS_BUILD_TESTS, actually alloc/free a block of memory for the mutex, so we can check for proper memory management and OOM handling. * dbus/dbus-dataslot.c: remove the mutex from DBusDataSlotAllocator and lock it manually when using it, to simplify fitting it into the global slots framework. * dbus/dbus-threads.c (init_static_locks): rework how we're handling global locks so they are easily shut down. * bus/policy.c (bus_policy_append_rule): fix * bus/test-main.c (main): check for memleaks * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make test suite check for memleaks * dbus/dbus-memory.c: add support in test mode for tracking number of outstanding blocks --- dbus/dbus-memory.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 8 deletions(-) (limited to 'dbus/dbus-memory.c') diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index 26766c0c..983c6e31 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -24,6 +24,7 @@ #include "dbus-memory.h" #include "dbus-internals.h" #include "dbus-sysdeps.h" +#include "dbus-list.h" #include @@ -81,6 +82,7 @@ static int fail_alloc_counter = _DBUS_INT_MAX; static dbus_bool_t guards = FALSE; static dbus_bool_t disable_mem_pools = FALSE; static dbus_bool_t backtrace_on_fail_alloc = FALSE; +static int n_blocks_outstanding = 0; /** value stored in guard padding for debugging buffer overrun */ #define GUARD_VALUE 0xdeadbeef @@ -215,6 +217,17 @@ _dbus_decrement_fail_alloc_counter (void) } } +/** + * Get the number of outstanding malloc()'d blocks. + * + * @returns number of blocks + */ +int +_dbus_get_malloc_blocks_outstanding (void) +{ + return n_blocks_outstanding; +} + /** * Where the block came from. */ @@ -372,11 +385,22 @@ dbus_malloc (size_t bytes) void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); + if (block) + n_blocks_outstanding += 1; + return set_guards (block, bytes, SOURCE_MALLOC); } #endif else - return malloc (bytes); + { + void *mem; + mem = malloc (bytes); +#ifdef DBUS_BUILD_TESTS + if (mem) + n_blocks_outstanding += 1; +#endif + return mem; + } } /** @@ -412,11 +436,21 @@ dbus_malloc0 (size_t bytes) void *block; block = calloc (bytes + GUARD_EXTRA_SIZE, 1); + if (block) + n_blocks_outstanding += 1; return set_guards (block, bytes, SOURCE_MALLOC_ZERO); } #endif else - return calloc (bytes, 1); + { + void *mem; + mem = calloc (bytes, 1); +#ifdef DBUS_BUILD_TESTS + if (mem) + n_blocks_outstanding += 1; +#endif + return mem; + } } /** @@ -462,9 +496,10 @@ dbus_realloc (void *memory, block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); - - /* old guards shouldn't have moved */ - check_guards (((unsigned char*)block) + GUARD_START_OFFSET); + + if (block) + /* old guards shouldn't have moved */ + check_guards (((unsigned char*)block) + GUARD_START_OFFSET); return set_guards (block, bytes, SOURCE_REALLOC); } @@ -473,13 +508,23 @@ dbus_realloc (void *memory, void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); + + if (block) + n_blocks_outstanding += 1; + return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } #endif else { - return realloc (memory, bytes); + void *mem; + mem = realloc (memory, bytes); +#ifdef DBUS_BUILD_TESTS + if (memory == NULL && mem != NULL) + n_blocks_outstanding += 1; +#endif + return mem; } } @@ -497,13 +542,28 @@ dbus_free (void *memory) { check_guards (memory); if (memory) - free (((unsigned char*)memory) - GUARD_START_OFFSET); + { + n_blocks_outstanding -= 1; + + _dbus_assert (n_blocks_outstanding >= 0); + + free (((unsigned char*)memory) - GUARD_START_OFFSET); + } + return; } #endif if (memory) /* we guarantee it's safe to free (NULL) */ - free (memory); + { +#ifdef DBUS_BUILD_TESTS + n_blocks_outstanding -= 1; + + _dbus_assert (n_blocks_outstanding >= 0); +#endif + + free (memory); + } } /** @@ -530,4 +590,89 @@ dbus_free_string_array (char **str_array) } } +/** + * _dbus_current_generation is used to track each + * time that dbus_shutdown() is called, so we can + * reinit things after it's been called. It is simply + * incremented each time we shut down. + */ +int _dbus_current_generation = 1; + +static DBusList *registered_globals = NULL; + +typedef struct +{ + DBusShutdownFunction func; + void *data; +} ShutdownClosure; + +/** + * The D-BUS library keeps some internal global variables, for example + * to cache the username of the current process. This function is + * used to free these global variables. It is really useful only for + * leak-checking cleanliness and the like. WARNING: this function is + * NOT thread safe, it must be called while NO other threads are using + * D-BUS. You cannot continue using D-BUS after calling this function, + * as it does things like free global mutexes created by + * dbus_threads_init(). To use a D-BUS function after calling + * dbus_shutdown(), you have to start over from scratch, e.g. calling + * dbus_threads_init() again. + */ +void +dbus_shutdown (void) +{ + DBusList *link; + + link = _dbus_list_get_first_link (®istered_globals); + while (link != NULL) + { + ShutdownClosure *c = link->data; + + (* c->func) (c->data); + + dbus_free (c); + + link = _dbus_list_get_next_link (®istered_globals, link); + } + + _dbus_list_clear (®istered_globals); + + _dbus_current_generation += 1; +} + +/** + * Register a cleanup function to be called exactly once + * the next time dbus_shutdown() is called. + * + * @param func the function + * @param data data to pass to the function + * @returns #FALSE on not enough memory + */ +dbus_bool_t +_dbus_register_shutdown_func (DBusShutdownFunction func, + void *data) +{ + ShutdownClosure *c; + + c = dbus_new (ShutdownClosure, 1); + + if (c == NULL) + return FALSE; + + c->func = func; + c->data = data; + + /* We prepend, then shutdown the list in order, so + * we shutdown last-registered stuff first which + * is right. + */ + if (!_dbus_list_prepend (®istered_globals, c)) + { + dbus_free (c); + return FALSE; + } + + return TRUE; +} + /** @} */ -- cgit