From 07a795f1db3b09beeec647643a4f263f617bc371 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 14 Feb 2003 04:54:55 +0000 Subject: 2003-02-14 Havoc Pennington * 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 --- dbus/dbus-internals.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-internals.h | 11 +++++++++++ dbus/dbus-memory.c | 12 +++++++++++- dbus/dbus-mempool.c | 25 +++++++++++++++++++++++-- dbus/dbus-message.c | 6 ++++++ 5 files changed, 103 insertions(+), 3 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 78a1b687..d51f5a97 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -391,4 +391,56 @@ _dbus_type_to_string (int type) } } +#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 */ + /** @} */ diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index f0baf46b..29dd41ce 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -142,6 +142,17 @@ void _dbus_verbose_bytes_of_string (const DBusString *str, 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 */ diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index 52a563e9..357e8be6 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -1,7 +1,7 @@ /* -*- 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 * @@ -22,6 +22,7 @@ */ #include "dbus-memory.h" +#include "dbus-internals.h" #include /** @@ -82,6 +83,9 @@ 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 @@ -100,6 +104,9 @@ dbus_malloc (size_t bytes) void* dbus_malloc0 (size_t bytes) { + if (_dbus_decrement_fail_alloc_counter ()) + return NULL; + if (bytes == 0) return NULL; else @@ -120,6 +127,9 @@ void* 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); diff --git a/dbus/dbus-mempool.c b/dbus/dbus-mempool.c index 05e3749b..3b233dd1 100644 --- a/dbus/dbus-mempool.c +++ b/dbus/dbus-mempool.c @@ -1,7 +1,7 @@ /* -*- 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 * @@ -195,6 +195,9 @@ _dbus_mem_pool_free (DBusMemPool *pool) void* _dbus_mem_pool_alloc (DBusMemPool *pool) { + if (_dbus_decrement_fail_alloc_counter ()) + return NULL; + if (pool->free_elements) { DBusFreedElement *element = pool->free_elements; @@ -216,7 +219,10 @@ _dbus_mem_pool_alloc (DBusMemPool *pool) /* 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 */ @@ -226,12 +232,27 @@ _dbus_mem_pool_alloc (DBusMemPool *pool) } 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; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 4287bd95..4ea2a631 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -2006,6 +2006,12 @@ decode_header_data (const DBusString *data, * 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. -- cgit