#include "dbus-internals.h"
#include "dbus-sysdeps.h"
#include "dbus-list.h"
+#include "dbus-threads.h"
#include <stdlib.h>
/**
* @{
*/
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
static dbus_bool_t debug_initialized = FALSE;
static int fail_nth = -1;
static size_t fail_size = 0;
static dbus_bool_t guards = FALSE;
static dbus_bool_t disable_mem_pools = FALSE;
static dbus_bool_t backtrace_on_fail_alloc = FALSE;
+static dbus_bool_t malloc_cannot_fail = FALSE;
static DBusAtomic n_blocks_outstanding = {0};
/** value stored in guard padding for debugging buffer overrun */
{
fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
fail_alloc_counter = fail_nth;
- _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
+ _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth);
}
if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
{
guards = TRUE;
- _dbus_verbose ("Will use malloc guards\n");
+ _dbus_verbose ("Will use dbus_malloc guards\n");
}
if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
{
backtrace_on_fail_alloc = TRUE;
- _dbus_verbose ("Will backtrace on failing a malloc\n");
+ _dbus_verbose ("Will backtrace on failing a dbus_malloc\n");
+ }
+
+ if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL)
+ {
+ malloc_cannot_fail = TRUE;
+ _dbus_verbose ("Will abort if system malloc() and friends fail\n");
}
}
}
return n_failures_per_failure;
}
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
/**
* Called when about to alloc some memory; if
* it returns #TRUE, then the allocation should
return FALSE;
}
}
-#endif /* DBUS_BUILD_TESTS */
+#endif /* DBUS_ENABLE_EMBEDDED_TESTS */
/**
* Get the number of outstanding malloc()'d blocks.
void*
dbus_malloc (size_t bytes)
{
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
_dbus_initialize_malloc_debug ();
if (_dbus_decrement_fail_alloc_counter ())
if (bytes == 0) /* some system mallocs handle this, some don't */
return NULL;
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
block = malloc (bytes + GUARD_EXTRA_SIZE);
if (block)
- _dbus_atomic_inc (&n_blocks_outstanding);
+ {
+ _dbus_atomic_inc (&n_blocks_outstanding);
+ }
+ else if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
+ (long) bytes, (long) GUARD_EXTRA_SIZE);
+ _dbus_abort ();
+ }
return set_guards (block, bytes, SOURCE_MALLOC);
}
{
void *mem;
mem = malloc (bytes);
-#ifdef DBUS_BUILD_TESTS
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
if (mem)
- _dbus_atomic_inc (&n_blocks_outstanding);
+ {
+ _dbus_atomic_inc (&n_blocks_outstanding);
+ }
+ else if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
+ _dbus_abort ();
+ }
#endif
+
return mem;
}
}
void*
dbus_malloc0 (size_t bytes)
{
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
_dbus_initialize_malloc_debug ();
if (_dbus_decrement_fail_alloc_counter ())
if (bytes == 0)
return NULL;
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
void *block;
block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
+
if (block)
- _dbus_atomic_inc (&n_blocks_outstanding);
+ {
+ _dbus_atomic_inc (&n_blocks_outstanding);
+ }
+ else if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n",
+ (long) bytes, (long) GUARD_EXTRA_SIZE);
+ _dbus_abort ();
+ }
+
return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
}
#endif
{
void *mem;
mem = calloc (bytes, 1);
-#ifdef DBUS_BUILD_TESTS
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
if (mem)
- _dbus_atomic_inc (&n_blocks_outstanding);
+ {
+ _dbus_atomic_inc (&n_blocks_outstanding);
+ }
+ else if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes);
+ _dbus_abort ();
+ }
#endif
+
return mem;
}
}
dbus_realloc (void *memory,
size_t bytes)
{
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
_dbus_initialize_malloc_debug ();
if (_dbus_decrement_fail_alloc_counter ())
dbus_free (memory);
return NULL;
}
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
bytes + GUARD_EXTRA_SIZE);
- old_bytes = *(dbus_uint32_t*)block;
- if (block && bytes >= old_bytes)
+ if (block == NULL)
+ {
+ if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n",
+ memory, (long) bytes, (long) GUARD_EXTRA_SIZE);
+ _dbus_abort ();
+ }
+
+ return NULL;
+ }
+
+ old_bytes = *(dbus_uint32_t*)block;
+ if (bytes >= old_bytes)
/* old guards shouldn't have moved */
check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
block = malloc (bytes + GUARD_EXTRA_SIZE);
if (block)
- _dbus_atomic_inc (&n_blocks_outstanding);
-
+ {
+ _dbus_atomic_inc (&n_blocks_outstanding);
+ }
+ else if (malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
+ (long) bytes, (long) GUARD_EXTRA_SIZE);
+ _dbus_abort ();
+ }
+
return set_guards (block, bytes, SOURCE_REALLOC_NULL);
}
}
{
void *mem;
mem = realloc (memory, bytes);
-#ifdef DBUS_BUILD_TESTS
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
+ if (mem == NULL && malloc_cannot_fail)
+ {
+ _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
+ _dbus_abort ();
+ }
+
if (memory == NULL && mem != NULL)
_dbus_atomic_inc (&n_blocks_outstanding);
#endif
void
dbus_free (void *memory)
{
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
if (guards)
{
check_guards (memory, TRUE);
if (memory) /* we guarantee it's safe to free (NULL) */
{
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
#ifdef DBUS_DISABLE_ASSERT
_dbus_atomic_dec (&n_blocks_outstanding);
#else
void *data; /**< Data for function */
};
-_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
+/* Protected by _DBUS_LOCK (shutdown_funcs) */
static ShutdownClosure *registered_globals = NULL;
/**
_dbus_register_shutdown_func (DBusShutdownFunction func,
void *data)
{
+ dbus_bool_t ok;
+
+ if (!_DBUS_LOCK (shutdown_funcs))
+ return FALSE;
+
+ ok = _dbus_register_shutdown_func_unlocked (func, data);
+ _DBUS_UNLOCK (shutdown_funcs);
+ return ok;
+}
+
+dbus_bool_t
+_dbus_register_shutdown_func_unlocked (DBusShutdownFunction func,
+ void *data)
+{
ShutdownClosure *c;
c = dbus_new (ShutdownClosure, 1);
c->func = func;
c->data = data;
- _DBUS_LOCK (shutdown_funcs);
-
c->next = registered_globals;
registered_globals = c;
- _DBUS_UNLOCK (shutdown_funcs);
-
return TRUE;
}
dbus_free (c);
}
+ /* We wrap this in the thread-initialization lock because
+ * dbus_threads_init() uses the current generation to tell whether
+ * we're initialized, so we need to make sure that un-initializing
+ * propagates into all threads. */
+ _dbus_threads_lock_platform_specific ();
_dbus_current_generation += 1;
+ _dbus_threads_unlock_platform_specific ();
}
/** @} */ /** End of public API docs block */
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
#include "dbus-test.h"
/**