D-Bus 1.6.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-memory.c D-Bus memory handling 00003 * 00004 * Copyright (C) 2002, 2003 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* end of public API docs */ 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 /* DBUS_BUILD_TESTS */ 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 /* set memory to anything but nul bytes */ 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 /* End of internals docs */ 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) /* some system mallocs handle this, some don't */ 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) /* guarantee this is safe */ 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 /* old guards shouldn't have moved */ 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) /* we guarantee it's safe to free (NULL) */ 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 /* End of public API docs block */ 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 /* End of private API docs block */ 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