2003-02-14 Havoc Pennington <hp@pobox.com>
+ * dbus/dbus-mempool.c: fail if the debug functions so indicate
+
+ * dbus/dbus-memory.c: fail if the debug functions indicate we
+ should
+
+ * dbus/dbus-internals.c (_dbus_set_fail_alloc_counter)
+ (_dbus_decrement_fail_alloc_counter): debug functions to
+ simulate memory allocation failures
+
+2003-02-14 Havoc Pennington <hp@pobox.com>
+
* dbus/dbus-errors.h (struct DBusError): add a word of padding
to DBusError
}
}
+#ifdef DBUS_BUILD_TESTS
+static int fail_alloc_counter = _DBUS_INT_MAX;
+/**
+ * Sets the number of allocations until we simulate a failed
+ * allocation. If set to 0, the next allocation to run
+ * fails; if set to 1, one succeeds then the next fails; etc.
+ * Set to _DBUS_INT_MAX to not fail anything.
+ *
+ * @param until_next_fail number of successful allocs before one fails
+ */
+void
+_dbus_set_fail_alloc_counter (int until_next_fail)
+{
+ fail_alloc_counter = until_next_fail;
+}
+
+/**
+ * Gets the number of successful allocs until we'll simulate
+ * a failed alloc.
+ *
+ * @returns current counter value
+ */
+int
+_dbus_get_fail_alloc_counter (void)
+{
+ return fail_alloc_counter;
+}
+
+/**
+ * Called when about to alloc some memory; if
+ * it returns #TRUE, then the allocation should
+ * fail. If it returns #FALSE, then the allocation
+ * should not fail.
+ *
+ * @returns #TRUE if this alloc should fail
+ */
+dbus_bool_t
+_dbus_decrement_fail_alloc_counter (void)
+{
+ if (fail_alloc_counter <= 0)
+ {
+ fail_alloc_counter = _DBUS_INT_MAX;
+ return TRUE;
+ }
+ else
+ {
+ fail_alloc_counter -= 1;
+ return FALSE;
+ }
+}
+#endif /* DBUS_BUILD_TESTS */
+
/** @} */
const char* _dbus_type_to_string (int type);
+#ifdef DBUS_BUILD_TESTS
+/* Memory debugging */
+void _dbus_set_fail_alloc_counter (int until_next_fail);
+int _dbus_get_fail_alloc_counter (void);
+dbus_bool_t _dbus_decrement_fail_alloc_counter (void);
+#else
+#define _dbus_set_fail_alloc_counter(n)
+#define _dbus_get_fail_alloc_counter _DBUS_INT_MAX
+#define _dbus_decrement_fail_alloc_counter FALSE
+#endif /* !DBUS_BUILD_TESTS */
+
DBUS_END_DECLS;
#endif /* DBUS_INTERNALS_H */
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-memory.c D-BUS memory handling
*
- * Copyright (C) 2002 Red Hat Inc.
+ * Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
*/
#include "dbus-memory.h"
+#include "dbus-internals.h"
#include <stdlib.h>
/**
void*
dbus_malloc (size_t bytes)
{
+ if (_dbus_decrement_fail_alloc_counter ())
+ return NULL;
+
if (bytes == 0) /* some system mallocs handle this, some don't */
return NULL;
else
void*
dbus_malloc0 (size_t bytes)
{
+ if (_dbus_decrement_fail_alloc_counter ())
+ return NULL;
+
if (bytes == 0)
return NULL;
else
dbus_realloc (void *memory,
size_t bytes)
{
+ if (_dbus_decrement_fail_alloc_counter ())
+ return NULL;
+
if (bytes == 0) /* guarantee this is safe */
{
dbus_free (memory);
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-mempool.h Memory pools
*
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
void*
_dbus_mem_pool_alloc (DBusMemPool *pool)
{
+ if (_dbus_decrement_fail_alloc_counter ())
+ return NULL;
+
if (pool->free_elements)
{
DBusFreedElement *element = pool->free_elements;
/* Need a new block */
DBusMemBlock *block;
int alloc_size;
-
+#ifdef DBUS_BUILD_TESTS
+ int saved_counter;
+#endif
+
if (pool->block_size <= _DBUS_INT_MAX / 4) /* avoid overflow */
{
/* use a larger block size for our next block */
}
alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->block_size;
+
+#ifdef DBUS_BUILD_TESTS
+ /* We save/restore the counter, so that memory pools won't
+ * cause a given function to have different number of
+ * allocations on different invocations. i.e. when testing
+ * we want consistent alloc patterns. So we skip our
+ * malloc here for purposes of failed alloc simulation.
+ */
+ saved_counter = _dbus_get_fail_alloc_counter ();
+ _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
+#endif
if (pool->zero_elements)
block = dbus_malloc0 (alloc_size);
else
block = dbus_malloc (alloc_size);
+#ifdef DBUS_BUILD_TESTS
+ _dbus_set_fail_alloc_counter (saved_counter);
+#endif
+
if (block == NULL)
return NULL;
* in. This function must always be called, even if no bytes were
* successfully read.
*
+ * @todo if we run out of memory in here, we offer no way for calling
+ * code to handle it, i.e. they can't re-run the message parsing
+ * attempt. Perhaps much of this code could be moved to pop_message()?
+ * But then that may need to distinguish NULL return for no messages
+ * from NULL return for errors.
+ *
* @param loader the loader.
* @param buffer the buffer.
* @param bytes_read number of bytes that were read into the buffer.