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 int 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
00242 dbus_bool_t
00243 _dbus_decrement_fail_alloc_counter (void)
00244 {
00245 _dbus_initialize_malloc_debug ();
00246
00247 if (fail_alloc_counter <= 0)
00248 {
00249 if (backtrace_on_fail_alloc)
00250 _dbus_print_backtrace ();
00251
00252 _dbus_verbose ("failure %d\n", n_failures_this_failure);
00253
00254 n_failures_this_failure += 1;
00255 if (n_failures_this_failure >= n_failures_per_failure)
00256 {
00257 if (fail_nth >= 0)
00258 fail_alloc_counter = fail_nth;
00259 else
00260 fail_alloc_counter = _DBUS_INT_MAX;
00261
00262 n_failures_this_failure = 0;
00263
00264 _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
00265 }
00266
00267 return TRUE;
00268 }
00269 else
00270 {
00271 fail_alloc_counter -= 1;
00272 return FALSE;
00273 }
00274 }
00275
00281 int
00282 _dbus_get_malloc_blocks_outstanding (void)
00283 {
00284 return n_blocks_outstanding;
00285 }
00286
00290 typedef enum
00291 {
00292 SOURCE_UNKNOWN,
00293 SOURCE_MALLOC,
00294 SOURCE_REALLOC,
00295 SOURCE_MALLOC_ZERO,
00296 SOURCE_REALLOC_NULL
00297 } BlockSource;
00298
00299 static const char*
00300 source_string (BlockSource source)
00301 {
00302 switch (source)
00303 {
00304 case SOURCE_UNKNOWN:
00305 return "unknown";
00306 case SOURCE_MALLOC:
00307 return "malloc";
00308 case SOURCE_REALLOC:
00309 return "realloc";
00310 case SOURCE_MALLOC_ZERO:
00311 return "malloc0";
00312 case SOURCE_REALLOC_NULL:
00313 return "realloc(NULL)";
00314 }
00315 _dbus_assert_not_reached ("Invalid malloc block source ID");
00316 return "invalid!";
00317 }
00318
00319 static void
00320 check_guards (void *free_block)
00321 {
00322 if (free_block != NULL)
00323 {
00324 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
00325 size_t requested_bytes = *(dbus_uint32_t*)block;
00326 BlockSource source = *(dbus_uint32_t*)(block + 4);
00327 unsigned int i;
00328 dbus_bool_t failed;
00329
00330 failed = FALSE;
00331
00332 #if 0
00333 _dbus_verbose ("Checking %d bytes request from source %s\n",
00334 requested_bytes, source_string (source));
00335 #endif
00336
00337 i = GUARD_INFO_SIZE;
00338 while (i < GUARD_START_OFFSET)
00339 {
00340 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
00341 if (value != GUARD_VALUE)
00342 {
00343 _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
00344 (long) requested_bytes, source_string (source),
00345 value, i, GUARD_VALUE);
00346 failed = TRUE;
00347 }
00348
00349 i += 4;
00350 }
00351
00352 i = GUARD_START_OFFSET + requested_bytes;
00353 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
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 end 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 if (failed)
00368 _dbus_assert_not_reached ("guard value corruption");
00369 }
00370 }
00371
00372 static void*
00373 set_guards (void *real_block,
00374 size_t requested_bytes,
00375 BlockSource source)
00376 {
00377 unsigned char *block = real_block;
00378 unsigned int i;
00379
00380 if (block == NULL)
00381 return NULL;
00382
00383 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
00384
00385 *((dbus_uint32_t*)block) = requested_bytes;
00386 *((dbus_uint32_t*)(block + 4)) = source;
00387
00388 i = GUARD_INFO_SIZE;
00389 while (i < GUARD_START_OFFSET)
00390 {
00391 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00392
00393 i += 4;
00394 }
00395
00396 i = GUARD_START_OFFSET + requested_bytes;
00397 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00398 {
00399 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00400
00401 i += 4;
00402 }
00403
00404 check_guards (block + GUARD_START_OFFSET);
00405
00406 return block + GUARD_START_OFFSET;
00407 }
00408
00409 #endif
00410
00412
00413
00429 void*
00430 dbus_malloc (size_t bytes)
00431 {
00432 #ifdef DBUS_BUILD_TESTS
00433 _dbus_initialize_malloc_debug ();
00434
00435 if (_dbus_decrement_fail_alloc_counter ())
00436 {
00437 _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
00438
00439 return NULL;
00440 }
00441 #endif
00442
00443 if (bytes == 0)
00444 return NULL;
00445 #ifdef DBUS_BUILD_TESTS
00446 else if (fail_size != 0 && bytes > fail_size)
00447 return NULL;
00448 else if (guards)
00449 {
00450 void *block;
00451
00452 block = malloc (bytes + GUARD_EXTRA_SIZE);
00453 if (block)
00454 n_blocks_outstanding += 1;
00455
00456 return set_guards (block, bytes, SOURCE_MALLOC);
00457 }
00458 #endif
00459 else
00460 {
00461 void *mem;
00462 mem = malloc (bytes);
00463 #ifdef DBUS_BUILD_TESTS
00464 if (mem)
00465 n_blocks_outstanding += 1;
00466 #endif
00467 return mem;
00468 }
00469 }
00470
00480 void*
00481 dbus_malloc0 (size_t bytes)
00482 {
00483 #ifdef DBUS_BUILD_TESTS
00484 _dbus_initialize_malloc_debug ();
00485
00486 if (_dbus_decrement_fail_alloc_counter ())
00487 {
00488 _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
00489
00490 return NULL;
00491 }
00492 #endif
00493
00494 if (bytes == 0)
00495 return NULL;
00496 #ifdef DBUS_BUILD_TESTS
00497 else if (fail_size != 0 && bytes > fail_size)
00498 return NULL;
00499 else if (guards)
00500 {
00501 void *block;
00502
00503 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
00504 if (block)
00505 n_blocks_outstanding += 1;
00506 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
00507 }
00508 #endif
00509 else
00510 {
00511 void *mem;
00512 mem = calloc (bytes, 1);
00513 #ifdef DBUS_BUILD_TESTS
00514 if (mem)
00515 n_blocks_outstanding += 1;
00516 #endif
00517 return mem;
00518 }
00519 }
00520
00531 void*
00532 dbus_realloc (void *memory,
00533 size_t bytes)
00534 {
00535 #ifdef DBUS_BUILD_TESTS
00536 _dbus_initialize_malloc_debug ();
00537
00538 if (_dbus_decrement_fail_alloc_counter ())
00539 {
00540 _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
00541
00542 return NULL;
00543 }
00544 #endif
00545
00546 if (bytes == 0)
00547 {
00548 dbus_free (memory);
00549 return NULL;
00550 }
00551 #ifdef DBUS_BUILD_TESTS
00552 else if (fail_size != 0 && bytes > fail_size)
00553 return NULL;
00554 else if (guards)
00555 {
00556 if (memory)
00557 {
00558 size_t old_bytes;
00559 void *block;
00560
00561 check_guards (memory);
00562
00563 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
00564 bytes + GUARD_EXTRA_SIZE);
00565
00566 old_bytes = *(dbus_uint32_t*)block;
00567 if (block && bytes >= old_bytes)
00568
00569 check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
00570
00571 return set_guards (block, bytes, SOURCE_REALLOC);
00572 }
00573 else
00574 {
00575 void *block;
00576
00577 block = malloc (bytes + GUARD_EXTRA_SIZE);
00578
00579 if (block)
00580 n_blocks_outstanding += 1;
00581
00582 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
00583 }
00584 }
00585 #endif
00586 else
00587 {
00588 void *mem;
00589 mem = realloc (memory, bytes);
00590 #ifdef DBUS_BUILD_TESTS
00591 if (memory == NULL && mem != NULL)
00592 n_blocks_outstanding += 1;
00593 #endif
00594 return mem;
00595 }
00596 }
00597
00604 void
00605 dbus_free (void *memory)
00606 {
00607 #ifdef DBUS_BUILD_TESTS
00608 if (guards)
00609 {
00610 check_guards (memory);
00611 if (memory)
00612 {
00613 n_blocks_outstanding -= 1;
00614
00615 _dbus_assert (n_blocks_outstanding >= 0);
00616
00617 free (((unsigned char*)memory) - GUARD_START_OFFSET);
00618 }
00619
00620 return;
00621 }
00622 #endif
00623
00624 if (memory)
00625 {
00626 #ifdef DBUS_BUILD_TESTS
00627 n_blocks_outstanding -= 1;
00628
00629 _dbus_assert (n_blocks_outstanding >= 0);
00630 #endif
00631
00632 free (memory);
00633 }
00634 }
00635
00642 void
00643 dbus_free_string_array (char **str_array)
00644 {
00645 if (str_array)
00646 {
00647 int i;
00648
00649 i = 0;
00650 while (str_array[i])
00651 {
00652 dbus_free (str_array[i]);
00653 i++;
00654 }
00655
00656 dbus_free (str_array);
00657 }
00658 }
00659
00661
00662
00675 int _dbus_current_generation = 1;
00676
00680 typedef struct ShutdownClosure ShutdownClosure;
00681
00685 struct ShutdownClosure
00686 {
00687 ShutdownClosure *next;
00688 DBusShutdownFunction func;
00689 void *data;
00690 };
00691
00692 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
00693 static ShutdownClosure *registered_globals = NULL;
00694
00703 dbus_bool_t
00704 _dbus_register_shutdown_func (DBusShutdownFunction func,
00705 void *data)
00706 {
00707 ShutdownClosure *c;
00708
00709 c = dbus_new (ShutdownClosure, 1);
00710
00711 if (c == NULL)
00712 return FALSE;
00713
00714 c->func = func;
00715 c->data = data;
00716
00717 _DBUS_LOCK (shutdown_funcs);
00718
00719 c->next = registered_globals;
00720 registered_globals = c;
00721
00722 _DBUS_UNLOCK (shutdown_funcs);
00723
00724 return TRUE;
00725 }
00726
00728
00729
00748 void
00749 dbus_shutdown (void)
00750 {
00751 while (registered_globals != NULL)
00752 {
00753 ShutdownClosure *c;
00754
00755 c = registered_globals;
00756 registered_globals = c->next;
00757
00758 (* c->func) (c->data);
00759
00760 dbus_free (c);
00761 }
00762
00763 _dbus_current_generation += 1;
00764 }
00765
00768 #ifdef DBUS_BUILD_TESTS
00769 #include "dbus-test.h"
00770
00776 dbus_bool_t
00777 _dbus_memory_test (void)
00778 {
00779 dbus_bool_t old_guards;
00780 void *p;
00781 size_t size;
00782
00783 old_guards = guards;
00784 guards = TRUE;
00785 p = dbus_malloc (4);
00786 if (p == NULL)
00787 _dbus_assert_not_reached ("no memory");
00788 for (size = 4; size < 256; size += 4)
00789 {
00790 p = dbus_realloc (p, size);
00791 if (p == NULL)
00792 _dbus_assert_not_reached ("no memory");
00793 }
00794 for (size = 256; size != 0; size -= 4)
00795 {
00796 p = dbus_realloc (p, size);
00797 if (p == NULL)
00798 _dbus_assert_not_reached ("no memory");
00799 }
00800 dbus_free (p);
00801 guards = old_guards;
00802 return TRUE;
00803 }
00804
00805 #endif