Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-memory.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 /* end of public API docs */ 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 %d bytes\n", 00141 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 %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n", 00344 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 %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n", 00359 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 /* End of internals docs */ 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 %d bytes\n", bytes); 00438 00439 return NULL; 00440 } 00441 #endif 00442 00443 if (bytes == 0) /* some system mallocs handle this, some don't */ 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 %d bytes\n", 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 %d bytes\n", bytes); 00541 00542 return NULL; 00543 } 00544 #endif 00545 00546 if (bytes == 0) /* guarantee this is safe */ 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 /* old guards shouldn't have moved */ 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) /* we guarantee it's safe to free (NULL) */ 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 /* End of public API docs block */ 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 /* End of private API docs block */ 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

Generated on Mon Jun 27 07:48:21 2005 for D-BUS by doxygen 1.3.7