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 "dbus-memory.h"
00025 #include "dbus-internals.h"
00026 #include "dbus-sysdeps.h"
00027 #include "dbus-list.h"
00028 #include <stdlib.h>
00029
00091
00098 #ifdef DBUS_BUILD_TESTS
00099 static dbus_bool_t debug_initialized = FALSE;
00100 static int fail_nth = -1;
00101 static size_t fail_size = 0;
00102 static int fail_alloc_counter = _DBUS_INT_MAX;
00103 static int n_failures_per_failure = 1;
00104 static int n_failures_this_failure = 0;
00105 static dbus_bool_t guards = FALSE;
00106 static dbus_bool_t disable_mem_pools = FALSE;
00107 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
00108 static DBusAtomic n_blocks_outstanding = {0};
00109
00111 #define GUARD_VALUE 0xdeadbeef
00112
00113 #define GUARD_INFO_SIZE 8
00114
00115 #define GUARD_START_PAD 16
00116
00117 #define GUARD_END_PAD 16
00118
00119 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
00120
00121 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
00122
00123 static void
00124 _dbus_initialize_malloc_debug (void)
00125 {
00126 if (!debug_initialized)
00127 {
00128 debug_initialized = TRUE;
00129
00130 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
00131 {
00132 fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
00133 fail_alloc_counter = fail_nth;
00134 _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
00135 }
00136
00137 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
00138 {
00139 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
00140 _dbus_verbose ("Will fail mallocs over %ld bytes\n",
00141 (long) fail_size);
00142 }
00143
00144 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
00145 {
00146 guards = TRUE;
00147 _dbus_verbose ("Will use malloc guards\n");
00148 }
00149
00150 if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
00151 {
00152 disable_mem_pools = TRUE;
00153 _dbus_verbose ("Will disable memory pools\n");
00154 }
00155
00156 if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
00157 {
00158 backtrace_on_fail_alloc = TRUE;
00159 _dbus_verbose ("Will backtrace on failing a malloc\n");
00160 }
00161 }
00162 }
00163
00169 dbus_bool_t
00170 _dbus_disable_mem_pools (void)
00171 {
00172 _dbus_initialize_malloc_debug ();
00173 return disable_mem_pools;
00174 }
00175
00184 void
00185 _dbus_set_fail_alloc_counter (int until_next_fail)
00186 {
00187 _dbus_initialize_malloc_debug ();
00188
00189 fail_alloc_counter = until_next_fail;
00190
00191 #if 0
00192 _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
00193 #endif
00194 }
00195
00202 int
00203 _dbus_get_fail_alloc_counter (void)
00204 {
00205 _dbus_initialize_malloc_debug ();
00206
00207 return fail_alloc_counter;
00208 }
00209
00216 void
00217 _dbus_set_fail_alloc_failures (int failures_per_failure)
00218 {
00219 n_failures_per_failure = failures_per_failure;
00220 }
00221
00228 int
00229 _dbus_get_fail_alloc_failures (void)
00230 {
00231 return n_failures_per_failure;
00232 }
00233
00234 #ifdef DBUS_BUILD_TESTS
00235
00243 dbus_bool_t
00244 _dbus_decrement_fail_alloc_counter (void)
00245 {
00246 _dbus_initialize_malloc_debug ();
00247
00248 if (fail_alloc_counter <= 0)
00249 {
00250 if (backtrace_on_fail_alloc)
00251 _dbus_print_backtrace ();
00252
00253 _dbus_verbose ("failure %d\n", n_failures_this_failure);
00254
00255 n_failures_this_failure += 1;
00256 if (n_failures_this_failure >= n_failures_per_failure)
00257 {
00258 if (fail_nth >= 0)
00259 fail_alloc_counter = fail_nth;
00260 else
00261 fail_alloc_counter = _DBUS_INT_MAX;
00262
00263 n_failures_this_failure = 0;
00264
00265 _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
00266 }
00267
00268 return TRUE;
00269 }
00270 else
00271 {
00272 fail_alloc_counter -= 1;
00273 return FALSE;
00274 }
00275 }
00276 #endif
00277
00283 int
00284 _dbus_get_malloc_blocks_outstanding (void)
00285 {
00286 return n_blocks_outstanding.value;
00287 }
00288
00292 typedef enum
00293 {
00294 SOURCE_UNKNOWN,
00295 SOURCE_MALLOC,
00296 SOURCE_REALLOC,
00297 SOURCE_MALLOC_ZERO,
00298 SOURCE_REALLOC_NULL
00299 } BlockSource;
00300
00301 static const char*
00302 source_string (BlockSource source)
00303 {
00304 switch (source)
00305 {
00306 case SOURCE_UNKNOWN:
00307 return "unknown";
00308 case SOURCE_MALLOC:
00309 return "malloc";
00310 case SOURCE_REALLOC:
00311 return "realloc";
00312 case SOURCE_MALLOC_ZERO:
00313 return "malloc0";
00314 case SOURCE_REALLOC_NULL:
00315 return "realloc(NULL)";
00316 }
00317 _dbus_assert_not_reached ("Invalid malloc block source ID");
00318 return "invalid!";
00319 }
00320
00321 static void
00322 check_guards (void *free_block,
00323 dbus_bool_t overwrite)
00324 {
00325 if (free_block != NULL)
00326 {
00327 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
00328 size_t requested_bytes = *(dbus_uint32_t*)block;
00329 BlockSource source = *(dbus_uint32_t*)(block + 4);
00330 unsigned int i;
00331 dbus_bool_t failed;
00332
00333 failed = FALSE;
00334
00335 #if 0
00336 _dbus_verbose ("Checking %d bytes request from source %s\n",
00337 requested_bytes, source_string (source));
00338 #endif
00339
00340 i = GUARD_INFO_SIZE;
00341 while (i < GUARD_START_OFFSET)
00342 {
00343 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00344 if (value != GUARD_VALUE)
00345 {
00346 _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
00347 (long) requested_bytes, source_string (source),
00348 value, i, GUARD_VALUE);
00349 failed = TRUE;
00350 }
00351
00352 i += 4;
00353 }
00354
00355 i = GUARD_START_OFFSET + requested_bytes;
00356 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00357 {
00358 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00359 if (value != GUARD_VALUE)
00360 {
00361 _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
00362 (long) requested_bytes, source_string (source),
00363 value, i, GUARD_VALUE);
00364 failed = TRUE;
00365 }
00366
00367 i += 4;
00368 }
00369
00370
00371 if (overwrite)
00372 memset (free_block, 'g', requested_bytes);
00373
00374 if (failed)
00375 _dbus_assert_not_reached ("guard value corruption");
00376 }
00377 }
00378
00379 static void*
00380 set_guards (void *real_block,
00381 size_t requested_bytes,
00382 BlockSource source)
00383 {
00384 unsigned char *block = real_block;
00385 unsigned int i;
00386
00387 if (block == NULL)
00388 return NULL;
00389
00390 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
00391
00392 *((dbus_uint32_t*)block) = requested_bytes;
00393 *((dbus_uint32_t*)(block + 4)) = source;
00394
00395 i = GUARD_INFO_SIZE;
00396 while (i < GUARD_START_OFFSET)
00397 {
00398 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00399
00400 i += 4;
00401 }
00402
00403 i = GUARD_START_OFFSET + requested_bytes;
00404 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00405 {
00406 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00407
00408 i += 4;
00409 }
00410
00411 check_guards (block + GUARD_START_OFFSET, FALSE);
00412
00413 return block + GUARD_START_OFFSET;
00414 }
00415
00416 #endif
00417
00419
00420
00439 void*
00440 dbus_malloc (size_t bytes)
00441 {
00442 #ifdef DBUS_BUILD_TESTS
00443 _dbus_initialize_malloc_debug ();
00444
00445 if (_dbus_decrement_fail_alloc_counter ())
00446 {
00447 _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
00448 return NULL;
00449 }
00450 #endif
00451
00452 if (bytes == 0)
00453 return NULL;
00454 #ifdef DBUS_BUILD_TESTS
00455 else if (fail_size != 0 && bytes > fail_size)
00456 return NULL;
00457 else if (guards)
00458 {
00459 void *block;
00460
00461 block = malloc (bytes + GUARD_EXTRA_SIZE);
00462 if (block)
00463 _dbus_atomic_inc (&n_blocks_outstanding);
00464
00465 return set_guards (block, bytes, SOURCE_MALLOC);
00466 }
00467 #endif
00468 else
00469 {
00470 void *mem;
00471 mem = malloc (bytes);
00472 #ifdef DBUS_BUILD_TESTS
00473 if (mem)
00474 _dbus_atomic_inc (&n_blocks_outstanding);
00475 #endif
00476 return mem;
00477 }
00478 }
00479
00492 void*
00493 dbus_malloc0 (size_t bytes)
00494 {
00495 #ifdef DBUS_BUILD_TESTS
00496 _dbus_initialize_malloc_debug ();
00497
00498 if (_dbus_decrement_fail_alloc_counter ())
00499 {
00500 _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
00501
00502 return NULL;
00503 }
00504 #endif
00505
00506 if (bytes == 0)
00507 return NULL;
00508 #ifdef DBUS_BUILD_TESTS
00509 else if (fail_size != 0 && bytes > fail_size)
00510 return NULL;
00511 else if (guards)
00512 {
00513 void *block;
00514
00515 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
00516 if (block)
00517 _dbus_atomic_inc (&n_blocks_outstanding);
00518 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
00519 }
00520 #endif
00521 else
00522 {
00523 void *mem;
00524 mem = calloc (bytes, 1);
00525 #ifdef DBUS_BUILD_TESTS
00526 if (mem)
00527 _dbus_atomic_inc (&n_blocks_outstanding);
00528 #endif
00529 return mem;
00530 }
00531 }
00532
00543 void*
00544 dbus_realloc (void *memory,
00545 size_t bytes)
00546 {
00547 #ifdef DBUS_BUILD_TESTS
00548 _dbus_initialize_malloc_debug ();
00549
00550 if (_dbus_decrement_fail_alloc_counter ())
00551 {
00552 _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
00553
00554 return NULL;
00555 }
00556 #endif
00557
00558 if (bytes == 0)
00559 {
00560 dbus_free (memory);
00561 return NULL;
00562 }
00563 #ifdef DBUS_BUILD_TESTS
00564 else if (fail_size != 0 && bytes > fail_size)
00565 return NULL;
00566 else if (guards)
00567 {
00568 if (memory)
00569 {
00570 size_t old_bytes;
00571 void *block;
00572
00573 check_guards (memory, FALSE);
00574
00575 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
00576 bytes + GUARD_EXTRA_SIZE);
00577
00578 old_bytes = *(dbus_uint32_t*)block;
00579 if (block && bytes >= old_bytes)
00580
00581 check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
00582
00583 return set_guards (block, bytes, SOURCE_REALLOC);
00584 }
00585 else
00586 {
00587 void *block;
00588
00589 block = malloc (bytes + GUARD_EXTRA_SIZE);
00590
00591 if (block)
00592 _dbus_atomic_inc (&n_blocks_outstanding);
00593
00594 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
00595 }
00596 }
00597 #endif
00598 else
00599 {
00600 void *mem;
00601 mem = realloc (memory, bytes);
00602 #ifdef DBUS_BUILD_TESTS
00603 if (memory == NULL && mem != NULL)
00604 _dbus_atomic_inc (&n_blocks_outstanding);
00605 #endif
00606 return mem;
00607 }
00608 }
00609
00616 void
00617 dbus_free (void *memory)
00618 {
00619 #ifdef DBUS_BUILD_TESTS
00620 if (guards)
00621 {
00622 check_guards (memory, TRUE);
00623 if (memory)
00624 {
00625 _dbus_atomic_dec (&n_blocks_outstanding);
00626
00627 _dbus_assert (n_blocks_outstanding.value >= 0);
00628
00629 free (((unsigned char*)memory) - GUARD_START_OFFSET);
00630 }
00631
00632 return;
00633 }
00634 #endif
00635
00636 if (memory)
00637 {
00638 #ifdef DBUS_BUILD_TESTS
00639 _dbus_atomic_dec (&n_blocks_outstanding);
00640
00641 _dbus_assert (n_blocks_outstanding.value >= 0);
00642 #endif
00643
00644 free (memory);
00645 }
00646 }
00647
00654 void
00655 dbus_free_string_array (char **str_array)
00656 {
00657 if (str_array)
00658 {
00659 int i;
00660
00661 i = 0;
00662 while (str_array[i])
00663 {
00664 dbus_free (str_array[i]);
00665 i++;
00666 }
00667
00668 dbus_free (str_array);
00669 }
00670 }
00671
00673
00674
00687 int _dbus_current_generation = 1;
00688
00692 typedef struct ShutdownClosure ShutdownClosure;
00693
00697 struct ShutdownClosure
00698 {
00699 ShutdownClosure *next;
00700 DBusShutdownFunction func;
00701 void *data;
00702 };
00703
00704 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
00705 static ShutdownClosure *registered_globals = NULL;
00706
00715 dbus_bool_t
00716 _dbus_register_shutdown_func (DBusShutdownFunction func,
00717 void *data)
00718 {
00719 ShutdownClosure *c;
00720
00721 c = dbus_new (ShutdownClosure, 1);
00722
00723 if (c == NULL)
00724 return FALSE;
00725
00726 c->func = func;
00727 c->data = data;
00728
00729 _DBUS_LOCK (shutdown_funcs);
00730
00731 c->next = registered_globals;
00732 registered_globals = c;
00733
00734 _DBUS_UNLOCK (shutdown_funcs);
00735
00736 return TRUE;
00737 }
00738
00740
00741
00785 void
00786 dbus_shutdown (void)
00787 {
00788 while (registered_globals != NULL)
00789 {
00790 ShutdownClosure *c;
00791
00792 c = registered_globals;
00793 registered_globals = c->next;
00794
00795 (* c->func) (c->data);
00796
00797 dbus_free (c);
00798 }
00799
00800 _dbus_current_generation += 1;
00801 }
00802
00805 #ifdef DBUS_BUILD_TESTS
00806 #include "dbus-test.h"
00807
00813 dbus_bool_t
00814 _dbus_memory_test (void)
00815 {
00816 dbus_bool_t old_guards;
00817 void *p;
00818 size_t size;
00819
00820 old_guards = guards;
00821 guards = TRUE;
00822 p = dbus_malloc (4);
00823 if (p == NULL)
00824 _dbus_assert_not_reached ("no memory");
00825 for (size = 4; size < 256; size += 4)
00826 {
00827 p = dbus_realloc (p, size);
00828 if (p == NULL)
00829 _dbus_assert_not_reached ("no memory");
00830 }
00831 for (size = 256; size != 0; size -= 4)
00832 {
00833 p = dbus_realloc (p, size);
00834 if (p == NULL)
00835 _dbus_assert_not_reached ("no memory");
00836 }
00837 dbus_free (p);
00838 guards = old_guards;
00839 return TRUE;
00840 }
00841
00842 #endif