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 "dbus-threads.h"
00030 #include <stdlib.h>
00031
00093
00100 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00101 static dbus_bool_t debug_initialized = FALSE;
00102 static int fail_nth = -1;
00103 static size_t fail_size = 0;
00104 static int fail_alloc_counter = _DBUS_INT_MAX;
00105 static int n_failures_per_failure = 1;
00106 static int n_failures_this_failure = 0;
00107 static dbus_bool_t guards = FALSE;
00108 static dbus_bool_t disable_mem_pools = FALSE;
00109 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
00110 static dbus_bool_t malloc_cannot_fail = FALSE;
00111 static DBusAtomic n_blocks_outstanding = {0};
00112
00114 #define GUARD_VALUE 0xdeadbeef
00115
00116 #define GUARD_INFO_SIZE 8
00117
00118 #define GUARD_START_PAD 16
00119
00120 #define GUARD_END_PAD 16
00121
00122 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
00123
00124 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
00125
00126 static void
00127 _dbus_initialize_malloc_debug (void)
00128 {
00129 if (!debug_initialized)
00130 {
00131 debug_initialized = TRUE;
00132
00133 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
00134 {
00135 fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
00136 fail_alloc_counter = fail_nth;
00137 _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth);
00138 }
00139
00140 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
00141 {
00142 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
00143 _dbus_verbose ("Will fail mallocs over %ld bytes\n",
00144 (long) fail_size);
00145 }
00146
00147 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
00148 {
00149 guards = TRUE;
00150 _dbus_verbose ("Will use dbus_malloc guards\n");
00151 }
00152
00153 if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
00154 {
00155 disable_mem_pools = TRUE;
00156 _dbus_verbose ("Will disable memory pools\n");
00157 }
00158
00159 if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
00160 {
00161 backtrace_on_fail_alloc = TRUE;
00162 _dbus_verbose ("Will backtrace on failing a dbus_malloc\n");
00163 }
00164
00165 if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL)
00166 {
00167 malloc_cannot_fail = TRUE;
00168 _dbus_verbose ("Will abort if system malloc() and friends fail\n");
00169 }
00170 }
00171 }
00172
00178 dbus_bool_t
00179 _dbus_disable_mem_pools (void)
00180 {
00181 _dbus_initialize_malloc_debug ();
00182 return disable_mem_pools;
00183 }
00184
00193 void
00194 _dbus_set_fail_alloc_counter (int until_next_fail)
00195 {
00196 _dbus_initialize_malloc_debug ();
00197
00198 fail_alloc_counter = until_next_fail;
00199
00200 #if 0
00201 _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
00202 #endif
00203 }
00204
00211 int
00212 _dbus_get_fail_alloc_counter (void)
00213 {
00214 _dbus_initialize_malloc_debug ();
00215
00216 return fail_alloc_counter;
00217 }
00218
00225 void
00226 _dbus_set_fail_alloc_failures (int failures_per_failure)
00227 {
00228 n_failures_per_failure = failures_per_failure;
00229 }
00230
00237 int
00238 _dbus_get_fail_alloc_failures (void)
00239 {
00240 return n_failures_per_failure;
00241 }
00242
00243 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00244
00252 dbus_bool_t
00253 _dbus_decrement_fail_alloc_counter (void)
00254 {
00255 _dbus_initialize_malloc_debug ();
00256 #ifdef DBUS_WIN_FIXME
00257 {
00258 static dbus_bool_t called = 0;
00259
00260 if (!called)
00261 {
00262 _dbus_verbose("TODO: memory allocation testing errors disabled for now\n");
00263 called = 1;
00264 }
00265 return FALSE;
00266 }
00267 #endif
00268
00269 if (fail_alloc_counter <= 0)
00270 {
00271 if (backtrace_on_fail_alloc)
00272 _dbus_print_backtrace ();
00273
00274 _dbus_verbose ("failure %d\n", n_failures_this_failure);
00275
00276 n_failures_this_failure += 1;
00277 if (n_failures_this_failure >= n_failures_per_failure)
00278 {
00279 if (fail_nth >= 0)
00280 fail_alloc_counter = fail_nth;
00281 else
00282 fail_alloc_counter = _DBUS_INT_MAX;
00283
00284 n_failures_this_failure = 0;
00285
00286 _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
00287 }
00288
00289 return TRUE;
00290 }
00291 else
00292 {
00293 fail_alloc_counter -= 1;
00294 return FALSE;
00295 }
00296 }
00297 #endif
00298
00304 int
00305 _dbus_get_malloc_blocks_outstanding (void)
00306 {
00307 return _dbus_atomic_get (&n_blocks_outstanding);
00308 }
00309
00313 typedef enum
00314 {
00315 SOURCE_UNKNOWN,
00316 SOURCE_MALLOC,
00317 SOURCE_REALLOC,
00318 SOURCE_MALLOC_ZERO,
00319 SOURCE_REALLOC_NULL
00320 } BlockSource;
00321
00322 static const char*
00323 source_string (BlockSource source)
00324 {
00325 switch (source)
00326 {
00327 case SOURCE_UNKNOWN:
00328 return "unknown";
00329 case SOURCE_MALLOC:
00330 return "malloc";
00331 case SOURCE_REALLOC:
00332 return "realloc";
00333 case SOURCE_MALLOC_ZERO:
00334 return "malloc0";
00335 case SOURCE_REALLOC_NULL:
00336 return "realloc(NULL)";
00337 }
00338 _dbus_assert_not_reached ("Invalid malloc block source ID");
00339 return "invalid!";
00340 }
00341
00342 static void
00343 check_guards (void *free_block,
00344 dbus_bool_t overwrite)
00345 {
00346 if (free_block != NULL)
00347 {
00348 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
00349 size_t requested_bytes = *(dbus_uint32_t*)block;
00350 BlockSource source = *(dbus_uint32_t*)(block + 4);
00351 unsigned int i;
00352 dbus_bool_t failed;
00353
00354 failed = FALSE;
00355
00356 #if 0
00357 _dbus_verbose ("Checking %d bytes request from source %s\n",
00358 requested_bytes, source_string (source));
00359 #endif
00360
00361 i = GUARD_INFO_SIZE;
00362 while (i < GUARD_START_OFFSET)
00363 {
00364 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00365 if (value != GUARD_VALUE)
00366 {
00367 _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
00368 (long) requested_bytes, source_string (source),
00369 value, i, GUARD_VALUE);
00370 failed = TRUE;
00371 }
00372
00373 i += 4;
00374 }
00375
00376 i = GUARD_START_OFFSET + requested_bytes;
00377 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00378 {
00379 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00380 if (value != GUARD_VALUE)
00381 {
00382 _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
00383 (long) requested_bytes, source_string (source),
00384 value, i, GUARD_VALUE);
00385 failed = TRUE;
00386 }
00387
00388 i += 4;
00389 }
00390
00391
00392 if (overwrite)
00393 memset (free_block, 'g', requested_bytes);
00394
00395 if (failed)
00396 _dbus_assert_not_reached ("guard value corruption");
00397 }
00398 }
00399
00400 static void*
00401 set_guards (void *real_block,
00402 size_t requested_bytes,
00403 BlockSource source)
00404 {
00405 unsigned char *block = real_block;
00406 unsigned int i;
00407
00408 if (block == NULL)
00409 return NULL;
00410
00411 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
00412
00413 *((dbus_uint32_t*)block) = requested_bytes;
00414 *((dbus_uint32_t*)(block + 4)) = source;
00415
00416 i = GUARD_INFO_SIZE;
00417 while (i < GUARD_START_OFFSET)
00418 {
00419 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00420
00421 i += 4;
00422 }
00423
00424 i = GUARD_START_OFFSET + requested_bytes;
00425 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00426 {
00427 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00428
00429 i += 4;
00430 }
00431
00432 check_guards (block + GUARD_START_OFFSET, FALSE);
00433
00434 return block + GUARD_START_OFFSET;
00435 }
00436
00437 #endif
00438
00440
00441
00460 void*
00461 dbus_malloc (size_t bytes)
00462 {
00463 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00464 _dbus_initialize_malloc_debug ();
00465
00466 if (_dbus_decrement_fail_alloc_counter ())
00467 {
00468 _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
00469 return NULL;
00470 }
00471 #endif
00472
00473 if (bytes == 0)
00474 return NULL;
00475 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00476 else if (fail_size != 0 && bytes > fail_size)
00477 return NULL;
00478 else if (guards)
00479 {
00480 void *block;
00481
00482 block = malloc (bytes + GUARD_EXTRA_SIZE);
00483 if (block)
00484 {
00485 _dbus_atomic_inc (&n_blocks_outstanding);
00486 }
00487 else if (malloc_cannot_fail)
00488 {
00489 _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
00490 (long) bytes, (long) GUARD_EXTRA_SIZE);
00491 _dbus_abort ();
00492 }
00493
00494 return set_guards (block, bytes, SOURCE_MALLOC);
00495 }
00496 #endif
00497 else
00498 {
00499 void *mem;
00500 mem = malloc (bytes);
00501
00502 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00503 if (mem)
00504 {
00505 _dbus_atomic_inc (&n_blocks_outstanding);
00506 }
00507 else if (malloc_cannot_fail)
00508 {
00509 _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
00510 _dbus_abort ();
00511 }
00512 #endif
00513
00514 return mem;
00515 }
00516 }
00517
00530 void*
00531 dbus_malloc0 (size_t bytes)
00532 {
00533 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00534 _dbus_initialize_malloc_debug ();
00535
00536 if (_dbus_decrement_fail_alloc_counter ())
00537 {
00538 _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
00539
00540 return NULL;
00541 }
00542 #endif
00543
00544 if (bytes == 0)
00545 return NULL;
00546 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00547 else if (fail_size != 0 && bytes > fail_size)
00548 return NULL;
00549 else if (guards)
00550 {
00551 void *block;
00552
00553 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
00554
00555 if (block)
00556 {
00557 _dbus_atomic_inc (&n_blocks_outstanding);
00558 }
00559 else if (malloc_cannot_fail)
00560 {
00561 _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n",
00562 (long) bytes, (long) GUARD_EXTRA_SIZE);
00563 _dbus_abort ();
00564 }
00565
00566 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
00567 }
00568 #endif
00569 else
00570 {
00571 void *mem;
00572 mem = calloc (bytes, 1);
00573
00574 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00575 if (mem)
00576 {
00577 _dbus_atomic_inc (&n_blocks_outstanding);
00578 }
00579 else if (malloc_cannot_fail)
00580 {
00581 _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes);
00582 _dbus_abort ();
00583 }
00584 #endif
00585
00586 return mem;
00587 }
00588 }
00589
00600 void*
00601 dbus_realloc (void *memory,
00602 size_t bytes)
00603 {
00604 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00605 _dbus_initialize_malloc_debug ();
00606
00607 if (_dbus_decrement_fail_alloc_counter ())
00608 {
00609 _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
00610
00611 return NULL;
00612 }
00613 #endif
00614
00615 if (bytes == 0)
00616 {
00617 dbus_free (memory);
00618 return NULL;
00619 }
00620 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00621 else if (fail_size != 0 && bytes > fail_size)
00622 return NULL;
00623 else if (guards)
00624 {
00625 if (memory)
00626 {
00627 size_t old_bytes;
00628 void *block;
00629
00630 check_guards (memory, FALSE);
00631
00632 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
00633 bytes + GUARD_EXTRA_SIZE);
00634
00635 if (block == NULL)
00636 {
00637 if (malloc_cannot_fail)
00638 {
00639 _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n",
00640 memory, (long) bytes, (long) GUARD_EXTRA_SIZE);
00641 _dbus_abort ();
00642 }
00643
00644 return NULL;
00645 }
00646
00647 old_bytes = *(dbus_uint32_t*)block;
00648 if (bytes >= old_bytes)
00649
00650 check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
00651
00652 return set_guards (block, bytes, SOURCE_REALLOC);
00653 }
00654 else
00655 {
00656 void *block;
00657
00658 block = malloc (bytes + GUARD_EXTRA_SIZE);
00659
00660 if (block)
00661 {
00662 _dbus_atomic_inc (&n_blocks_outstanding);
00663 }
00664 else if (malloc_cannot_fail)
00665 {
00666 _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
00667 (long) bytes, (long) GUARD_EXTRA_SIZE);
00668 _dbus_abort ();
00669 }
00670
00671 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
00672 }
00673 }
00674 #endif
00675 else
00676 {
00677 void *mem;
00678 mem = realloc (memory, bytes);
00679
00680 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00681 if (mem == NULL && malloc_cannot_fail)
00682 {
00683 _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
00684 _dbus_abort ();
00685 }
00686
00687 if (memory == NULL && mem != NULL)
00688 _dbus_atomic_inc (&n_blocks_outstanding);
00689 #endif
00690 return mem;
00691 }
00692 }
00693
00700 void
00701 dbus_free (void *memory)
00702 {
00703 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00704 if (guards)
00705 {
00706 check_guards (memory, TRUE);
00707 if (memory)
00708 {
00709 #ifdef DBUS_DISABLE_ASSERT
00710 _dbus_atomic_dec (&n_blocks_outstanding);
00711 #else
00712 dbus_int32_t old_value;
00713
00714 old_value = _dbus_atomic_dec (&n_blocks_outstanding);
00715 _dbus_assert (old_value >= 1);
00716 #endif
00717
00718 free (((unsigned char*)memory) - GUARD_START_OFFSET);
00719 }
00720
00721 return;
00722 }
00723 #endif
00724
00725 if (memory)
00726 {
00727 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00728 #ifdef DBUS_DISABLE_ASSERT
00729 _dbus_atomic_dec (&n_blocks_outstanding);
00730 #else
00731 dbus_int32_t old_value;
00732
00733 old_value = _dbus_atomic_dec (&n_blocks_outstanding);
00734 _dbus_assert (old_value >= 1);
00735 #endif
00736 #endif
00737
00738 free (memory);
00739 }
00740 }
00741
00748 void
00749 dbus_free_string_array (char **str_array)
00750 {
00751 if (str_array)
00752 {
00753 int i;
00754
00755 i = 0;
00756 while (str_array[i])
00757 {
00758 dbus_free (str_array[i]);
00759 i++;
00760 }
00761
00762 dbus_free (str_array);
00763 }
00764 }
00765
00767
00768
00781 int _dbus_current_generation = 1;
00782
00786 typedef struct ShutdownClosure ShutdownClosure;
00787
00791 struct ShutdownClosure
00792 {
00793 ShutdownClosure *next;
00794 DBusShutdownFunction func;
00795 void *data;
00796 };
00797
00798
00799 static ShutdownClosure *registered_globals = NULL;
00800
00809 dbus_bool_t
00810 _dbus_register_shutdown_func (DBusShutdownFunction func,
00811 void *data)
00812 {
00813 dbus_bool_t ok;
00814
00815 if (!_DBUS_LOCK (shutdown_funcs))
00816 return FALSE;
00817
00818 ok = _dbus_register_shutdown_func_unlocked (func, data);
00819 _DBUS_UNLOCK (shutdown_funcs);
00820 return ok;
00821 }
00822
00823 dbus_bool_t
00824 _dbus_register_shutdown_func_unlocked (DBusShutdownFunction func,
00825 void *data)
00826 {
00827 ShutdownClosure *c;
00828
00829 c = dbus_new (ShutdownClosure, 1);
00830
00831 if (c == NULL)
00832 return FALSE;
00833
00834 c->func = func;
00835 c->data = data;
00836
00837 c->next = registered_globals;
00838 registered_globals = c;
00839
00840 return TRUE;
00841 }
00842
00844
00845
00896 void
00897 dbus_shutdown (void)
00898 {
00899 while (registered_globals != NULL)
00900 {
00901 ShutdownClosure *c;
00902
00903 c = registered_globals;
00904 registered_globals = c->next;
00905
00906 (* c->func) (c->data);
00907
00908 dbus_free (c);
00909 }
00910
00911
00912
00913
00914
00915 _dbus_threads_lock_platform_specific ();
00916 _dbus_current_generation += 1;
00917 _dbus_threads_unlock_platform_specific ();
00918 }
00919
00922 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00923 #include "dbus-test.h"
00924
00930 dbus_bool_t
00931 _dbus_memory_test (void)
00932 {
00933 dbus_bool_t old_guards;
00934 void *p;
00935 size_t size;
00936
00937 old_guards = guards;
00938 guards = TRUE;
00939 p = dbus_malloc (4);
00940 if (p == NULL)
00941 _dbus_assert_not_reached ("no memory");
00942 for (size = 4; size < 256; size += 4)
00943 {
00944 p = dbus_realloc (p, size);
00945 if (p == NULL)
00946 _dbus_assert_not_reached ("no memory");
00947 }
00948 for (size = 256; size != 0; size -= 4)
00949 {
00950 p = dbus_realloc (p, size);
00951 if (p == NULL)
00952 _dbus_assert_not_reached ("no memory");
00953 }
00954 dbus_free (p);
00955 guards = old_guards;
00956 return TRUE;
00957 }
00958
00959 #endif