00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "dbus-memory.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-sysdeps.h"
00028 #include "dbus-list.h"
00029 #include <stdlib.h>
00030
00092
00099 #ifdef DBUS_BUILD_TESTS
00100 static dbus_bool_t debug_initialized = FALSE;
00101 static int fail_nth = -1;
00102 static size_t fail_size = 0;
00103 static int fail_alloc_counter = _DBUS_INT_MAX;
00104 static int n_failures_per_failure = 1;
00105 static int n_failures_this_failure = 0;
00106 static dbus_bool_t guards = FALSE;
00107 static dbus_bool_t disable_mem_pools = FALSE;
00108 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
00109 static DBusAtomic n_blocks_outstanding = {0};
00110
00112 #define GUARD_VALUE 0xdeadbeef
00113
00114 #define GUARD_INFO_SIZE 8
00115
00116 #define GUARD_START_PAD 16
00117
00118 #define GUARD_END_PAD 16
00119
00120 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
00121
00122 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
00123
00124 static void
00125 _dbus_initialize_malloc_debug (void)
00126 {
00127 if (!debug_initialized)
00128 {
00129 debug_initialized = TRUE;
00130
00131 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
00132 {
00133 fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
00134 fail_alloc_counter = fail_nth;
00135 _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
00136 }
00137
00138 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
00139 {
00140 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
00141 _dbus_verbose ("Will fail mallocs over %ld bytes\n",
00142 (long) fail_size);
00143 }
00144
00145 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
00146 {
00147 guards = TRUE;
00148 _dbus_verbose ("Will use malloc guards\n");
00149 }
00150
00151 if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
00152 {
00153 disable_mem_pools = TRUE;
00154 _dbus_verbose ("Will disable memory pools\n");
00155 }
00156
00157 if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
00158 {
00159 backtrace_on_fail_alloc = TRUE;
00160 _dbus_verbose ("Will backtrace on failing a malloc\n");
00161 }
00162 }
00163 }
00164
00170 dbus_bool_t
00171 _dbus_disable_mem_pools (void)
00172 {
00173 _dbus_initialize_malloc_debug ();
00174 return disable_mem_pools;
00175 }
00176
00185 void
00186 _dbus_set_fail_alloc_counter (int until_next_fail)
00187 {
00188 _dbus_initialize_malloc_debug ();
00189
00190 fail_alloc_counter = until_next_fail;
00191
00192 #if 0
00193 _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
00194 #endif
00195 }
00196
00203 int
00204 _dbus_get_fail_alloc_counter (void)
00205 {
00206 _dbus_initialize_malloc_debug ();
00207
00208 return fail_alloc_counter;
00209 }
00210
00217 void
00218 _dbus_set_fail_alloc_failures (int failures_per_failure)
00219 {
00220 n_failures_per_failure = failures_per_failure;
00221 }
00222
00229 int
00230 _dbus_get_fail_alloc_failures (void)
00231 {
00232 return n_failures_per_failure;
00233 }
00234
00235 #ifdef DBUS_BUILD_TESTS
00236 static dbus_bool_t called = 0;
00245 dbus_bool_t
00246 _dbus_decrement_fail_alloc_counter (void)
00247 {
00248 _dbus_initialize_malloc_debug ();
00249 #ifdef DBUS_WIN_FIXME
00250 {
00251 if (!called)
00252 {
00253 _dbus_verbose("TODO: memory allocation testing errors disabled for now\n");
00254 called = 1;
00255 }
00256 return FALSE;
00257 }
00258 #endif
00259
00260 if (fail_alloc_counter <= 0)
00261 {
00262 if (backtrace_on_fail_alloc)
00263 _dbus_print_backtrace ();
00264
00265 _dbus_verbose ("failure %d\n", n_failures_this_failure);
00266
00267 n_failures_this_failure += 1;
00268 if (n_failures_this_failure >= n_failures_per_failure)
00269 {
00270 if (fail_nth >= 0)
00271 fail_alloc_counter = fail_nth;
00272 else
00273 fail_alloc_counter = _DBUS_INT_MAX;
00274
00275 n_failures_this_failure = 0;
00276
00277 _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
00278 }
00279
00280 return TRUE;
00281 }
00282 else
00283 {
00284 fail_alloc_counter -= 1;
00285 return FALSE;
00286 }
00287 }
00288 #endif
00289
00295 int
00296 _dbus_get_malloc_blocks_outstanding (void)
00297 {
00298 return _dbus_atomic_get (&n_blocks_outstanding);
00299 }
00300
00304 typedef enum
00305 {
00306 SOURCE_UNKNOWN,
00307 SOURCE_MALLOC,
00308 SOURCE_REALLOC,
00309 SOURCE_MALLOC_ZERO,
00310 SOURCE_REALLOC_NULL
00311 } BlockSource;
00312
00313 static const char*
00314 source_string (BlockSource source)
00315 {
00316 switch (source)
00317 {
00318 case SOURCE_UNKNOWN:
00319 return "unknown";
00320 case SOURCE_MALLOC:
00321 return "malloc";
00322 case SOURCE_REALLOC:
00323 return "realloc";
00324 case SOURCE_MALLOC_ZERO:
00325 return "malloc0";
00326 case SOURCE_REALLOC_NULL:
00327 return "realloc(NULL)";
00328 }
00329 _dbus_assert_not_reached ("Invalid malloc block source ID");
00330 return "invalid!";
00331 }
00332
00333 static void
00334 check_guards (void *free_block,
00335 dbus_bool_t overwrite)
00336 {
00337 if (free_block != NULL)
00338 {
00339 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
00340 size_t requested_bytes = *(dbus_uint32_t*)block;
00341 BlockSource source = *(dbus_uint32_t*)(block + 4);
00342 unsigned int i;
00343 dbus_bool_t failed;
00344
00345 failed = FALSE;
00346
00347 #if 0
00348 _dbus_verbose ("Checking %d bytes request from source %s\n",
00349 requested_bytes, source_string (source));
00350 #endif
00351
00352 i = GUARD_INFO_SIZE;
00353 while (i < GUARD_START_OFFSET)
00354 {
00355 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00356 if (value != GUARD_VALUE)
00357 {
00358 _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
00359 (long) requested_bytes, source_string (source),
00360 value, i, GUARD_VALUE);
00361 failed = TRUE;
00362 }
00363
00364 i += 4;
00365 }
00366
00367 i = GUARD_START_OFFSET + requested_bytes;
00368 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00369 {
00370 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00371 if (value != GUARD_VALUE)
00372 {
00373 _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
00374 (long) requested_bytes, source_string (source),
00375 value, i, GUARD_VALUE);
00376 failed = TRUE;
00377 }
00378
00379 i += 4;
00380 }
00381
00382
00383 if (overwrite)
00384 memset (free_block, 'g', requested_bytes);
00385
00386 if (failed)
00387 _dbus_assert_not_reached ("guard value corruption");
00388 }
00389 }
00390
00391 static void*
00392 set_guards (void *real_block,
00393 size_t requested_bytes,
00394 BlockSource source)
00395 {
00396 unsigned char *block = real_block;
00397 unsigned int i;
00398
00399 if (block == NULL)
00400 return NULL;
00401
00402 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
00403
00404 *((dbus_uint32_t*)block) = requested_bytes;
00405 *((dbus_uint32_t*)(block + 4)) = source;
00406
00407 i = GUARD_INFO_SIZE;
00408 while (i < GUARD_START_OFFSET)
00409 {
00410 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00411
00412 i += 4;
00413 }
00414
00415 i = GUARD_START_OFFSET + requested_bytes;
00416 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00417 {
00418 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00419
00420 i += 4;
00421 }
00422
00423 check_guards (block + GUARD_START_OFFSET, FALSE);
00424
00425 return block + GUARD_START_OFFSET;
00426 }
00427
00428 #endif
00429
00431
00432
00451 void*
00452 dbus_malloc (size_t bytes)
00453 {
00454 #ifdef DBUS_BUILD_TESTS
00455 _dbus_initialize_malloc_debug ();
00456
00457 if (_dbus_decrement_fail_alloc_counter ())
00458 {
00459 _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
00460 return NULL;
00461 }
00462 #endif
00463
00464 if (bytes == 0)
00465 return NULL;
00466 #ifdef DBUS_BUILD_TESTS
00467 else if (fail_size != 0 && bytes > fail_size)
00468 return NULL;
00469 else if (guards)
00470 {
00471 void *block;
00472
00473 block = malloc (bytes + GUARD_EXTRA_SIZE);
00474 if (block)
00475 _dbus_atomic_inc (&n_blocks_outstanding);
00476
00477 return set_guards (block, bytes, SOURCE_MALLOC);
00478 }
00479 #endif
00480 else
00481 {
00482 void *mem;
00483 mem = malloc (bytes);
00484 #ifdef DBUS_BUILD_TESTS
00485 if (mem)
00486 _dbus_atomic_inc (&n_blocks_outstanding);
00487 #endif
00488 return mem;
00489 }
00490 }
00491
00504 void*
00505 dbus_malloc0 (size_t bytes)
00506 {
00507 #ifdef DBUS_BUILD_TESTS
00508 _dbus_initialize_malloc_debug ();
00509
00510 if (_dbus_decrement_fail_alloc_counter ())
00511 {
00512 _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
00513
00514 return NULL;
00515 }
00516 #endif
00517
00518 if (bytes == 0)
00519 return NULL;
00520 #ifdef DBUS_BUILD_TESTS
00521 else if (fail_size != 0 && bytes > fail_size)
00522 return NULL;
00523 else if (guards)
00524 {
00525 void *block;
00526
00527 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
00528 if (block)
00529 _dbus_atomic_inc (&n_blocks_outstanding);
00530 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
00531 }
00532 #endif
00533 else
00534 {
00535 void *mem;
00536 mem = calloc (bytes, 1);
00537 #ifdef DBUS_BUILD_TESTS
00538 if (mem)
00539 _dbus_atomic_inc (&n_blocks_outstanding);
00540 #endif
00541 return mem;
00542 }
00543 }
00544
00555 void*
00556 dbus_realloc (void *memory,
00557 size_t bytes)
00558 {
00559 #ifdef DBUS_BUILD_TESTS
00560 _dbus_initialize_malloc_debug ();
00561
00562 if (_dbus_decrement_fail_alloc_counter ())
00563 {
00564 _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
00565
00566 return NULL;
00567 }
00568 #endif
00569
00570 if (bytes == 0)
00571 {
00572 dbus_free (memory);
00573 return NULL;
00574 }
00575 #ifdef DBUS_BUILD_TESTS
00576 else if (fail_size != 0 && bytes > fail_size)
00577 return NULL;
00578 else if (guards)
00579 {
00580 if (memory)
00581 {
00582 size_t old_bytes;
00583 void *block;
00584
00585 check_guards (memory, FALSE);
00586
00587 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
00588 bytes + GUARD_EXTRA_SIZE);
00589
00590 old_bytes = *(dbus_uint32_t*)block;
00591 if (block && bytes >= old_bytes)
00592
00593 check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
00594
00595 return set_guards (block, bytes, SOURCE_REALLOC);
00596 }
00597 else
00598 {
00599 void *block;
00600
00601 block = malloc (bytes + GUARD_EXTRA_SIZE);
00602
00603 if (block)
00604 _dbus_atomic_inc (&n_blocks_outstanding);
00605
00606 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
00607 }
00608 }
00609 #endif
00610 else
00611 {
00612 void *mem;
00613 mem = realloc (memory, bytes);
00614 #ifdef DBUS_BUILD_TESTS
00615 if (memory == NULL && mem != NULL)
00616 _dbus_atomic_inc (&n_blocks_outstanding);
00617 #endif
00618 return mem;
00619 }
00620 }
00621
00628 void
00629 dbus_free (void *memory)
00630 {
00631 #ifdef DBUS_BUILD_TESTS
00632 if (guards)
00633 {
00634 check_guards (memory, TRUE);
00635 if (memory)
00636 {
00637 #ifdef DBUS_DISABLE_ASSERT
00638 _dbus_atomic_dec (&n_blocks_outstanding);
00639 #else
00640 dbus_int32_t old_value;
00641
00642 old_value = _dbus_atomic_dec (&n_blocks_outstanding);
00643 _dbus_assert (old_value >= 1);
00644 #endif
00645
00646 free (((unsigned char*)memory) - GUARD_START_OFFSET);
00647 }
00648
00649 return;
00650 }
00651 #endif
00652
00653 if (memory)
00654 {
00655 #ifdef DBUS_BUILD_TESTS
00656 #ifdef DBUS_DISABLE_ASSERT
00657 _dbus_atomic_dec (&n_blocks_outstanding);
00658 #else
00659 dbus_int32_t old_value;
00660
00661 old_value = _dbus_atomic_dec (&n_blocks_outstanding);
00662 _dbus_assert (old_value >= 1);
00663 #endif
00664 #endif
00665
00666 free (memory);
00667 }
00668 }
00669
00676 void
00677 dbus_free_string_array (char **str_array)
00678 {
00679 if (str_array)
00680 {
00681 int i;
00682
00683 i = 0;
00684 while (str_array[i])
00685 {
00686 dbus_free (str_array[i]);
00687 i++;
00688 }
00689
00690 dbus_free (str_array);
00691 }
00692 }
00693
00695
00696
00709 int _dbus_current_generation = 1;
00710
00714 typedef struct ShutdownClosure ShutdownClosure;
00715
00719 struct ShutdownClosure
00720 {
00721 ShutdownClosure *next;
00722 DBusShutdownFunction func;
00723 void *data;
00724 };
00725
00726 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
00727 static ShutdownClosure *registered_globals = NULL;
00728
00737 dbus_bool_t
00738 _dbus_register_shutdown_func (DBusShutdownFunction func,
00739 void *data)
00740 {
00741 ShutdownClosure *c;
00742
00743 c = dbus_new (ShutdownClosure, 1);
00744
00745 if (c == NULL)
00746 return FALSE;
00747
00748 c->func = func;
00749 c->data = data;
00750
00751 _DBUS_LOCK (shutdown_funcs);
00752
00753 c->next = registered_globals;
00754 registered_globals = c;
00755
00756 _DBUS_UNLOCK (shutdown_funcs);
00757
00758 return TRUE;
00759 }
00760
00762
00763
00807 void
00808 dbus_shutdown (void)
00809 {
00810 while (registered_globals != NULL)
00811 {
00812 ShutdownClosure *c;
00813
00814 c = registered_globals;
00815 registered_globals = c->next;
00816
00817 (* c->func) (c->data);
00818
00819 dbus_free (c);
00820 }
00821
00822 _dbus_current_generation += 1;
00823 }
00824
00827 #ifdef DBUS_BUILD_TESTS
00828 #include "dbus-test.h"
00829
00835 dbus_bool_t
00836 _dbus_memory_test (void)
00837 {
00838 dbus_bool_t old_guards;
00839 void *p;
00840 size_t size;
00841
00842 old_guards = guards;
00843 guards = TRUE;
00844 p = dbus_malloc (4);
00845 if (p == NULL)
00846 _dbus_assert_not_reached ("no memory");
00847 for (size = 4; size < 256; size += 4)
00848 {
00849 p = dbus_realloc (p, size);
00850 if (p == NULL)
00851 _dbus_assert_not_reached ("no memory");
00852 }
00853 for (size = 256; size != 0; size -= 4)
00854 {
00855 p = dbus_realloc (p, size);
00856 if (p == NULL)
00857 _dbus_assert_not_reached ("no memory");
00858 }
00859 dbus_free (p);
00860 guards = old_guards;
00861 return TRUE;
00862 }
00863
00864 #endif