1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-memory.c D-Bus memory handling 3 * 4 * Copyright (C) 2002, 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-memory.h" 25 #include "dbus-internals.h" 26 #include "dbus-sysdeps.h" 27 #include "dbus-list.h" 28 #include <stdlib.h> 29 30 /** 31 * @defgroup DBusMemory Memory Allocation 32 * @ingroup DBus 33 * @brief dbus_malloc(), dbus_free(), etc. 34 * 35 * Functions and macros related to allocating and releasing 36 * blocks of memory. 37 * 38 */ 39 40 /** 41 * @defgroup DBusMemoryInternals Memory allocation implementation details 42 * @ingroup DBusInternals 43 * @brief internals of dbus_malloc() etc. 44 * 45 * Implementation details related to allocating and releasing blocks 46 * of memory. 47 */ 48 49 /** 50 * @addtogroup DBusMemory 51 * 52 * @{ 53 */ 54 55 /** 56 * @def dbus_new 57 * 58 * Safe macro for using dbus_malloc(). Accepts the type 59 * to allocate and the number of type instances to 60 * allocate as arguments, and returns a memory block 61 * cast to the desired type, instead of as a void*. 62 * 63 * @param type type name to allocate 64 * @param count number of instances in the allocated array 65 * @returns the new memory block or #NULL on failure 66 */ 67 68 /** 69 * @def dbus_new0 70 * 71 * Safe macro for using dbus_malloc0(). Accepts the type 72 * to allocate and the number of type instances to 73 * allocate as arguments, and returns a memory block 74 * cast to the desired type, instead of as a void*. 75 * The allocated array is initialized to all-bits-zero. 76 * 77 * @param type type name to allocate 78 * @param count number of instances in the allocated array 79 * @returns the new memory block or #NULL on failure 80 */ 81 82 /** 83 * @typedef DBusFreeFunction 84 * 85 * The type of a function which frees a block of memory. 86 * 87 * @param memory the memory to free 88 */ 89 90 /** @} */ /* end of public API docs */ 91 92 /** 93 * @addtogroup DBusMemoryInternals 94 * 95 * @{ 96 */ 97 98 #ifdef DBUS_BUILD_TESTS 99 static dbus_bool_t debug_initialized = FALSE; 100 static int fail_nth = -1; 101 static size_t fail_size = 0; 102 static int fail_alloc_counter = _DBUS_INT_MAX; 103 static int n_failures_per_failure = 1; 104 static int n_failures_this_failure = 0; 105 static dbus_bool_t guards = FALSE; 106 static dbus_bool_t disable_mem_pools = FALSE; 107 static dbus_bool_t backtrace_on_fail_alloc = FALSE; 108 static DBusAtomic n_blocks_outstanding = {0}; 109 110 /** value stored in guard padding for debugging buffer overrun */ 111 #define GUARD_VALUE 0xdeadbeef 112 /** size of the information about the block stored in guard mode */ 113 #define GUARD_INFO_SIZE 8 114 /** size of the GUARD_VALUE-filled padding after the header info */ 115 #define GUARD_START_PAD 16 116 /** size of the GUARD_VALUE-filled padding at the end of the block */ 117 #define GUARD_END_PAD 16 118 /** size of stuff at start of block */ 119 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE) 120 /** total extra size over the requested allocation for guard stuff */ 121 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD) 122 123 static void 124 _dbus_initialize_malloc_debug (void) 125 { 126 if (!debug_initialized) 127 { 128 debug_initialized = TRUE; 129 130 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL) 131 { 132 fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH")); 133 fail_alloc_counter = fail_nth; 134 _dbus_verbose ("Will fail malloc every %d times\n", fail_nth); 135 } 136 137 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL) 138 { 139 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN")); 140 _dbus_verbose ("Will fail mallocs over %ld bytes\n", 141 (long) fail_size); 142 } 143 144 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL) 145 { 146 guards = TRUE; 147 _dbus_verbose ("Will use malloc guards\n"); 148 } 149 150 if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL) 151 { 152 disable_mem_pools = TRUE; 153 _dbus_verbose ("Will disable memory pools\n"); 154 } 155 156 if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL) 157 { 158 backtrace_on_fail_alloc = TRUE; 159 _dbus_verbose ("Will backtrace on failing a malloc\n"); 160 } 161 } 162 } 163 164 /** 165 * Whether to turn off mem pools, useful for leak checking. 166 * 167 * @returns #TRUE if mempools should not be used. 168 */ 169 dbus_bool_t 170 _dbus_disable_mem_pools (void) 171 { 172 _dbus_initialize_malloc_debug (); 173 return disable_mem_pools; 174 } 175 176 /** 177 * Sets the number of allocations until we simulate a failed 178 * allocation. If set to 0, the next allocation to run 179 * fails; if set to 1, one succeeds then the next fails; etc. 180 * Set to _DBUS_INT_MAX to not fail anything. 181 * 182 * @param until_next_fail number of successful allocs before one fails 183 */ 184 void 185 _dbus_set_fail_alloc_counter (int until_next_fail) 186 { 187 _dbus_initialize_malloc_debug (); 188 189 fail_alloc_counter = until_next_fail; 190 191 #if 0 192 _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter); 193 #endif 194 } 195 196 /** 197 * Gets the number of successful allocs until we'll simulate 198 * a failed alloc. 199 * 200 * @returns current counter value 201 */ 202 int 203 _dbus_get_fail_alloc_counter (void) 204 { 205 _dbus_initialize_malloc_debug (); 206 207 return fail_alloc_counter; 208 } 209 210 /** 211 * Sets how many mallocs to fail when the fail alloc counter reaches 212 * 0. 213 * 214 * @param failures_per_failure number to fail 215 */ 216 void 217 _dbus_set_fail_alloc_failures (int failures_per_failure) 218 { 219 n_failures_per_failure = failures_per_failure; 220 } 221 222 /** 223 * Gets the number of failures we'll have when the fail malloc 224 * counter reaches 0. 225 * 226 * @returns number of failures planned 227 */ 228 int 229 _dbus_get_fail_alloc_failures (void) 230 { 231 return n_failures_per_failure; 232 } 233 234 #ifdef DBUS_BUILD_TESTS 235 /** 236 * Called when about to alloc some memory; if 237 * it returns #TRUE, then the allocation should 238 * fail. If it returns #FALSE, then the allocation 239 * should not fail. 240 * 241 * @returns #TRUE if this alloc should fail 242 */ 243 dbus_bool_t 244 _dbus_decrement_fail_alloc_counter (void) 245 { 246 _dbus_initialize_malloc_debug (); 247 248 if (fail_alloc_counter <= 0) 249 { 250 if (backtrace_on_fail_alloc) 251 _dbus_print_backtrace (); 252 253 _dbus_verbose ("failure %d\n", n_failures_this_failure); 254 255 n_failures_this_failure += 1; 256 if (n_failures_this_failure >= n_failures_per_failure) 257 { 258 if (fail_nth >= 0) 259 fail_alloc_counter = fail_nth; 260 else 261 fail_alloc_counter = _DBUS_INT_MAX; 262 263 n_failures_this_failure = 0; 264 265 _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter); 266 } 267 268 return TRUE; 269 } 270 else 271 { 272 fail_alloc_counter -= 1; 273 return FALSE; 274 } 275 } 276 #endif /* DBUS_BUILD_TESTS */ 277 278 /** 279 * Get the number of outstanding malloc()'d blocks. 280 * 281 * @returns number of blocks 282 */ 283 int 284 _dbus_get_malloc_blocks_outstanding (void) 285 { 286 return n_blocks_outstanding.value; 287 } 288 289 /** 290 * Where the block came from. 291 */ 292 typedef enum 293 { 294 SOURCE_UNKNOWN, 295 SOURCE_MALLOC, 296 SOURCE_REALLOC, 297 SOURCE_MALLOC_ZERO, 298 SOURCE_REALLOC_NULL 299 } BlockSource; 300 301 static const char* 302 source_string (BlockSource source) 303 { 304 switch (source) 305 { 306 case SOURCE_UNKNOWN: 307 return "unknown"; 308 case SOURCE_MALLOC: 309 return "malloc"; 310 case SOURCE_REALLOC: 311 return "realloc"; 312 case SOURCE_MALLOC_ZERO: 313 return "malloc0"; 314 case SOURCE_REALLOC_NULL: 315 return "realloc(NULL)"; 316 } 317 _dbus_assert_not_reached ("Invalid malloc block source ID"); 318 return "invalid!"; 319 } 320 321 static void 322 check_guards (void *free_block, 323 dbus_bool_t overwrite) 324 { 325 if (free_block != NULL) 326 { 327 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET; 328 size_t requested_bytes = *(dbus_uint32_t*)block; 329 BlockSource source = *(dbus_uint32_t*)(block + 4); 330 unsigned int i; 331 dbus_bool_t failed; 332 333 failed = FALSE; 334 335 #if 0 336 _dbus_verbose ("Checking %d bytes request from source %s\n", 337 requested_bytes, source_string (source)); 338 #endif 339 340 i = GUARD_INFO_SIZE; 341 while (i < GUARD_START_OFFSET) 342 { 343 dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; 344 if (value != GUARD_VALUE) 345 { 346 _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n", 347 (long) requested_bytes, source_string (source), 348 value, i, GUARD_VALUE); 349 failed = TRUE; 350 } 351 352 i += 4; 353 } 354 355 i = GUARD_START_OFFSET + requested_bytes; 356 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) 357 { 358 dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; 359 if (value != GUARD_VALUE) 360 { 361 _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n", 362 (long) requested_bytes, source_string (source), 363 value, i, GUARD_VALUE); 364 failed = TRUE; 365 } 366 367 i += 4; 368 } 369 370 /* set memory to anything but nul bytes */ 371 if (overwrite) 372 memset (free_block, 'g', requested_bytes); 373 374 if (failed) 375 _dbus_assert_not_reached ("guard value corruption"); 376 } 377 } 378 379 static void* 380 set_guards (void *real_block, 381 size_t requested_bytes, 382 BlockSource source) 383 { 384 unsigned char *block = real_block; 385 unsigned int i; 386 387 if (block == NULL) 388 return NULL; 389 390 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE); 391 392 *((dbus_uint32_t*)block) = requested_bytes; 393 *((dbus_uint32_t*)(block + 4)) = source; 394 395 i = GUARD_INFO_SIZE; 396 while (i < GUARD_START_OFFSET) 397 { 398 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; 399 400 i += 4; 401 } 402 403 i = GUARD_START_OFFSET + requested_bytes; 404 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) 405 { 406 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; 407 408 i += 4; 409 } 410 411 check_guards (block + GUARD_START_OFFSET, FALSE); 412 413 return block + GUARD_START_OFFSET; 414 } 415 416 #endif 417 418 /** @} */ /* End of internals docs */ 419 420 421 /** 422 * @addtogroup DBusMemory 423 * 424 * @{ 425 */ 426 427 /** 428 * Allocates the given number of bytes, as with standard 429 * malloc(). Guaranteed to return #NULL if bytes is zero 430 * on all platforms. Returns #NULL if the allocation fails. 431 * The memory must be released with dbus_free(). 432 * 433 * dbus_malloc() memory is NOT safe to free with regular free() from 434 * the C library. Free it with dbus_free() only. 435 * 436 * @param bytes number of bytes to allocate 437 * @return allocated memory, or #NULL if the allocation fails. 438 */ 439 void* 440 dbus_malloc (size_t bytes) 441 { 442 #ifdef DBUS_BUILD_TESTS 443 _dbus_initialize_malloc_debug (); 444 445 if (_dbus_decrement_fail_alloc_counter ()) 446 { 447 _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); 448 return NULL; 449 } 450 #endif 451 452 if (bytes == 0) /* some system mallocs handle this, some don't */ 453 return NULL; 454 #ifdef DBUS_BUILD_TESTS 455 else if (fail_size != 0 && bytes > fail_size) 456 return NULL; 457 else if (guards) 458 { 459 void *block; 460 461 block = malloc (bytes + GUARD_EXTRA_SIZE); 462 if (block) 463 _dbus_atomic_inc (&n_blocks_outstanding); 464 465 return set_guards (block, bytes, SOURCE_MALLOC); 466 } 467 #endif 468 else 469 { 470 void *mem; 471 mem = malloc (bytes); 472 #ifdef DBUS_BUILD_TESTS 473 if (mem) 474 _dbus_atomic_inc (&n_blocks_outstanding); 475 #endif 476 return mem; 477 } 478 } 479 480 /** 481 * Allocates the given number of bytes, as with standard malloc(), but 482 * all bytes are initialized to zero as with calloc(). Guaranteed to 483 * return #NULL if bytes is zero on all platforms. Returns #NULL if the 484 * allocation fails. The memory must be released with dbus_free(). 485 * 486 * dbus_malloc0() memory is NOT safe to free with regular free() from 487 * the C library. Free it with dbus_free() only. 488 * 489 * @param bytes number of bytes to allocate 490 * @return allocated memory, or #NULL if the allocation fails. 491 */ 492 void* 493 dbus_malloc0 (size_t bytes) 494 { 495 #ifdef DBUS_BUILD_TESTS 496 _dbus_initialize_malloc_debug (); 497 498 if (_dbus_decrement_fail_alloc_counter ()) 499 { 500 _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes); 501 502 return NULL; 503 } 504 #endif 505 506 if (bytes == 0) 507 return NULL; 508 #ifdef DBUS_BUILD_TESTS 509 else if (fail_size != 0 && bytes > fail_size) 510 return NULL; 511 else if (guards) 512 { 513 void *block; 514 515 block = calloc (bytes + GUARD_EXTRA_SIZE, 1); 516 if (block) 517 _dbus_atomic_inc (&n_blocks_outstanding); 518 return set_guards (block, bytes, SOURCE_MALLOC_ZERO); 519 } 520 #endif 521 else 522 { 523 void *mem; 524 mem = calloc (bytes, 1); 525 #ifdef DBUS_BUILD_TESTS 526 if (mem) 527 _dbus_atomic_inc (&n_blocks_outstanding); 528 #endif 529 return mem; 530 } 531 } 532 533 /** 534 * Resizes a block of memory previously allocated by dbus_malloc() or 535 * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes 536 * is zero on all platforms. Returns #NULL if the resize fails. 537 * If the resize fails, the memory is not freed. 538 * 539 * @param memory block to be resized 540 * @param bytes new size of the memory block 541 * @return allocated memory, or #NULL if the resize fails. 542 */ 543 void* 544 dbus_realloc (void *memory, 545 size_t bytes) 546 { 547 #ifdef DBUS_BUILD_TESTS 548 _dbus_initialize_malloc_debug (); 549 550 if (_dbus_decrement_fail_alloc_counter ()) 551 { 552 _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes); 553 554 return NULL; 555 } 556 #endif 557 558 if (bytes == 0) /* guarantee this is safe */ 559 { 560 dbus_free (memory); 561 return NULL; 562 } 563 #ifdef DBUS_BUILD_TESTS 564 else if (fail_size != 0 && bytes > fail_size) 565 return NULL; 566 else if (guards) 567 { 568 if (memory) 569 { 570 size_t old_bytes; 571 void *block; 572 573 check_guards (memory, FALSE); 574 575 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, 576 bytes + GUARD_EXTRA_SIZE); 577 578 old_bytes = *(dbus_uint32_t*)block; 579 if (block && bytes >= old_bytes) 580 /* old guards shouldn't have moved */ 581 check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); 582 583 return set_guards (block, bytes, SOURCE_REALLOC); 584 } 585 else 586 { 587 void *block; 588 589 block = malloc (bytes + GUARD_EXTRA_SIZE); 590 591 if (block) 592 _dbus_atomic_inc (&n_blocks_outstanding); 593 594 return set_guards (block, bytes, SOURCE_REALLOC_NULL); 595 } 596 } 597 #endif 598 else 599 { 600 void *mem; 601 mem = realloc (memory, bytes); 602 #ifdef DBUS_BUILD_TESTS 603 if (memory == NULL && mem != NULL) 604 _dbus_atomic_inc (&n_blocks_outstanding); 605 #endif 606 return mem; 607 } 608 } 609 610 /** 611 * Frees a block of memory previously allocated by dbus_malloc() or 612 * dbus_malloc0(). If passed #NULL, does nothing. 613 * 614 * @param memory block to be freed 615 */ 616 void 617 dbus_free (void *memory) 618 { 619 #ifdef DBUS_BUILD_TESTS 620 if (guards) 621 { 622 check_guards (memory, TRUE); 623 if (memory) 624 { 625 _dbus_atomic_dec (&n_blocks_outstanding); 626 627 _dbus_assert (n_blocks_outstanding.value >= 0); 628 629 free (((unsigned char*)memory) - GUARD_START_OFFSET); 630 } 631 632 return; 633 } 634 #endif 635 636 if (memory) /* we guarantee it's safe to free (NULL) */ 637 { 638 #ifdef DBUS_BUILD_TESTS 639 _dbus_atomic_dec (&n_blocks_outstanding); 640 641 _dbus_assert (n_blocks_outstanding.value >= 0); 642 #endif 643 644 free (memory); 645 } 646 } 647 648 /** 649 * Frees a #NULL-terminated array of strings. 650 * If passed #NULL, does nothing. 651 * 652 * @param str_array the array to be freed 653 */ 654 void 655 dbus_free_string_array (char **str_array) 656 { 657 if (str_array) 658 { 659 int i; 660 661 i = 0; 662 while (str_array[i]) 663 { 664 dbus_free (str_array[i]); 665 i++; 666 } 667 668 dbus_free (str_array); 669 } 670 } 671 672 /** @} */ /* End of public API docs block */ 673 674 675 /** 676 * @addtogroup DBusMemoryInternals 677 * 678 * @{ 679 */ 680 681 /** 682 * _dbus_current_generation is used to track each 683 * time that dbus_shutdown() is called, so we can 684 * reinit things after it's been called. It is simply 685 * incremented each time we shut down. 686 */ 687 int _dbus_current_generation = 1; 688 689 /** 690 * Represents a function to be called on shutdown. 691 */ 692 typedef struct ShutdownClosure ShutdownClosure; 693 694 /** 695 * This struct represents a function to be called on shutdown. 696 */ 697 struct ShutdownClosure 698 { 699 ShutdownClosure *next; /**< Next ShutdownClosure */ 700 DBusShutdownFunction func; /**< Function to call */ 701 void *data; /**< Data for function */ 702 }; 703 704 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs); 705 static ShutdownClosure *registered_globals = NULL; 706 707 /** 708 * Register a cleanup function to be called exactly once 709 * the next time dbus_shutdown() is called. 710 * 711 * @param func the function 712 * @param data data to pass to the function 713 * @returns #FALSE on not enough memory 714 */ 715 dbus_bool_t 716 _dbus_register_shutdown_func (DBusShutdownFunction func, 717 void *data) 718 { 719 ShutdownClosure *c; 720 721 c = dbus_new (ShutdownClosure, 1); 722 723 if (c == NULL) 724 return FALSE; 725 726 c->func = func; 727 c->data = data; 728 729 _DBUS_LOCK (shutdown_funcs); 730 731 c->next = registered_globals; 732 registered_globals = c; 733 734 _DBUS_UNLOCK (shutdown_funcs); 735 736 return TRUE; 737 } 738 739 /** @} */ /* End of private API docs block */ 740 741 742 /** 743 * @addtogroup DBusMemory 744 * 745 * @{ 746 */ 747 748 /** 749 * Frees all memory allocated internally by libdbus and 750 * reverses the effects of dbus_threads_init(). libdbus keeps internal 751 * global variables, for example caches and thread locks, and it 752 * can be useful to free these internal data structures. 753 * 754 * dbus_shutdown() does NOT free memory that was returned 755 * to the application. It only returns libdbus-internal 756 * data structures. 757 * 758 * You MUST free all memory and release all reference counts 759 * returned to you by libdbus prior to calling dbus_shutdown(). 760 * 761 * You can't continue to use any D-Bus objects, such as connections, 762 * that were allocated prior to dbus_shutdown(). You can, however, 763 * start over; call dbus_threads_init() again, create new connections, 764 * and so forth. 765 * 766 * WARNING: dbus_shutdown() is NOT thread safe, it must be called 767 * while NO other threads are using D-Bus. (Remember, you have to free 768 * all D-Bus objects and memory before you call dbus_shutdown(), so no 769 * thread can be using libdbus.) 770 * 771 * The purpose of dbus_shutdown() is to allow applications to get 772 * clean output from memory leak checkers. dbus_shutdown() may also be 773 * useful if you want to dlopen() libdbus instead of linking to it, 774 * and want to be able to unload the library again. 775 * 776 * There is absolutely no requirement to call dbus_shutdown() - in fact, 777 * most applications won't bother and should not feel guilty. 778 * 779 * You have to know that nobody is using libdbus in your application's 780 * process before you can call dbus_shutdown(). One implication of this 781 * is that calling dbus_shutdown() from a library is almost certainly 782 * wrong, since you don't know what the rest of the app is up to. 783 * 784 */ 785 void 786 dbus_shutdown (void) 787 { 788 while (registered_globals != NULL) 789 { 790 ShutdownClosure *c; 791 792 c = registered_globals; 793 registered_globals = c->next; 794 795 (* c->func) (c->data); 796 797 dbus_free (c); 798 } 799 800 _dbus_current_generation += 1; 801 } 802 803 /** @} */ /** End of public API docs block */ 804 805 #ifdef DBUS_BUILD_TESTS 806 #include "dbus-test.h" 807 808 /** 809 * @ingroup DBusMemoryInternals 810 * Unit test for DBusMemory 811 * @returns #TRUE on success. 812 */ 813 dbus_bool_t 814 _dbus_memory_test (void) 815 { 816 dbus_bool_t old_guards; 817 void *p; 818 size_t size; 819 820 old_guards = guards; 821 guards = TRUE; 822 p = dbus_malloc (4); 823 if (p == NULL) 824 _dbus_assert_not_reached ("no memory"); 825 for (size = 4; size < 256; size += 4) 826 { 827 p = dbus_realloc (p, size); 828 if (p == NULL) 829 _dbus_assert_not_reached ("no memory"); 830 } 831 for (size = 256; size != 0; size -= 4) 832 { 833 p = dbus_realloc (p, size); 834 if (p == NULL) 835 _dbus_assert_not_reached ("no memory"); 836 } 837 dbus_free (p); 838 guards = old_guards; 839 return TRUE; 840 } 841 842 #endif 843