summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-memory.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-24 03:16:58 +0000
committerHavoc Pennington <hp@redhat.com>2003-03-24 03:16:58 +0000
commitc3af5ccdbc22e8990d04ec2f89ad1f2e053655e9 (patch)
tree6010b0b9a2be255b3ff3ac9f62e4c04ce57aef83 /dbus/dbus-memory.c
parenta26607ab68bf0878f23d2dbddec781b4b760d034 (diff)
2003-03-23 Havoc Pennington <hp@pobox.com>
* 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
Diffstat (limited to 'dbus/dbus-memory.c')
-rw-r--r--dbus/dbus-memory.c161
1 files changed, 153 insertions, 8 deletions
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 <stdlib.h>
@@ -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
@@ -216,6 +218,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.
*/
typedef enum
@@ -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 (&registered_globals);
+ while (link != NULL)
+ {
+ ShutdownClosure *c = link->data;
+
+ (* c->func) (c->data);
+
+ dbus_free (c);
+
+ link = _dbus_list_get_next_link (&registered_globals, link);
+ }
+
+ _dbus_list_clear (&registered_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 (&registered_globals, c))
+ {
+ dbus_free (c);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/** @} */