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