1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-internals.c random utility stuff (internal to D-Bus implementation) 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 #include "dbus-internals.h" 24 #include "dbus-protocol.h" 25 #include "dbus-marshal-basic.h" 26 #include "dbus-test.h" 27 #include <stdio.h> 28 #include <stdarg.h> 29 #include <string.h> 30 #include <stdlib.h> 31 32 #ifdef DBUS_ANDROID_LOG 33 #define LOG_TAG "libdbus" 34 #include <cutils/log.h> 35 #endif /* DBUS_ANDROID_LOG */ 36 37 /** 38 * @defgroup DBusInternals D-Bus secret internal implementation details 39 * @brief Documentation useful when developing or debugging D-Bus itself. 40 * 41 */ 42 43 /** 44 * @defgroup DBusInternalsUtils Utilities and portability 45 * @ingroup DBusInternals 46 * @brief Utility functions (_dbus_assert(), _dbus_warn(), etc.) 47 * @{ 48 */ 49 50 /** 51 * @def _dbus_assert 52 * 53 * Aborts with an error message if the condition is false. 54 * 55 * @param condition condition which must be true. 56 */ 57 58 /** 59 * @def _dbus_assert_not_reached 60 * 61 * Aborts with an error message if called. 62 * The given explanation will be printed. 63 * 64 * @param explanation explanation of what happened if the code was reached. 65 */ 66 67 /** 68 * @def _DBUS_N_ELEMENTS 69 * 70 * Computes the number of elements in a fixed-size array using 71 * sizeof(). 72 * 73 * @param array the array to count elements in. 74 */ 75 76 /** 77 * @def _DBUS_POINTER_TO_INT 78 * 79 * Safely casts a void* to an integer; should only be used on void* 80 * that actually contain integers, for example one created with 81 * _DBUS_INT_TO_POINTER. Only guaranteed to preserve 32 bits. 82 * (i.e. it's used to store 32-bit ints in pointers, but 83 * can't be used to store 64-bit pointers in ints.) 84 * 85 * @param pointer pointer to extract an integer from. 86 */ 87 /** 88 * @def _DBUS_INT_TO_POINTER 89 * 90 * Safely stuffs an integer into a pointer, to be extracted later with 91 * _DBUS_POINTER_TO_INT. Only guaranteed to preserve 32 bits. 92 * 93 * @param integer the integer to stuff into a pointer. 94 */ 95 /** 96 * @def _DBUS_ZERO 97 * 98 * Sets all bits in an object to zero. 99 * 100 * @param object the object to be zeroed. 101 */ 102 /** 103 * @def _DBUS_INT16_MIN 104 * 105 * Minimum value of type "int16" 106 */ 107 /** 108 * @def _DBUS_INT16_MAX 109 * 110 * Maximum value of type "int16" 111 */ 112 /** 113 * @def _DBUS_UINT16_MAX 114 * 115 * Maximum value of type "uint16" 116 */ 117 118 /** 119 * @def _DBUS_INT32_MIN 120 * 121 * Minimum value of type "int32" 122 */ 123 /** 124 * @def _DBUS_INT32_MAX 125 * 126 * Maximum value of type "int32" 127 */ 128 /** 129 * @def _DBUS_UINT32_MAX 130 * 131 * Maximum value of type "uint32" 132 */ 133 134 /** 135 * @def _DBUS_INT_MIN 136 * 137 * Minimum value of type "int" 138 */ 139 /** 140 * @def _DBUS_INT_MAX 141 * 142 * Maximum value of type "int" 143 */ 144 /** 145 * @def _DBUS_UINT_MAX 146 * 147 * Maximum value of type "uint" 148 */ 149 150 /** 151 * @typedef DBusForeachFunction 152 * 153 * Used to iterate over each item in a collection, such as 154 * a DBusList. 155 */ 156 157 /** 158 * @def _DBUS_LOCK_NAME 159 * 160 * Expands to name of a global lock variable. 161 */ 162 163 /** 164 * @def _DBUS_DEFINE_GLOBAL_LOCK 165 * 166 * Defines a global lock variable with the given name. 167 * The lock must be added to the list to initialize 168 * in dbus_threads_init(). 169 */ 170 171 /** 172 * @def _DBUS_DECLARE_GLOBAL_LOCK 173 * 174 * Expands to declaration of a global lock defined 175 * with _DBUS_DEFINE_GLOBAL_LOCK. 176 * The lock must be added to the list to initialize 177 * in dbus_threads_init(). 178 */ 179 180 /** 181 * @def _DBUS_LOCK 182 * 183 * Locks a global lock 184 */ 185 186 /** 187 * @def _DBUS_UNLOCK 188 * 189 * Unlocks a global lock 190 */ 191 192 /** 193 * Fixed "out of memory" error message, just to avoid 194 * making up a different string every time and wasting 195 * space. 196 */ 197 const char _dbus_no_memory_message[] = "Not enough memory"; 198 199 static dbus_bool_t warn_initted = FALSE; 200 static dbus_bool_t fatal_warnings = FALSE; 201 static dbus_bool_t fatal_warnings_on_check_failed = TRUE; 202 203 static void 204 init_warnings(void) 205 { 206 if (!warn_initted) 207 { 208 const char *s; 209 s = _dbus_getenv ("DBUS_FATAL_WARNINGS"); 210 if (s && *s) 211 { 212 if (*s == '0') 213 { 214 fatal_warnings = FALSE; 215 fatal_warnings_on_check_failed = FALSE; 216 } 217 else if (*s == '1') 218 { 219 fatal_warnings = TRUE; 220 fatal_warnings_on_check_failed = TRUE; 221 } 222 else 223 { 224 fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'", 225 s); 226 } 227 } 228 229 warn_initted = TRUE; 230 } 231 } 232 233 /** 234 * Prints a warning message to stderr. Can optionally be made to exit 235 * fatally by setting DBUS_FATAL_WARNINGS, but this is rarely 236 * used. This function should be considered pretty much equivalent to 237 * fprintf(stderr). _dbus_warn_check_failed() on the other hand is 238 * suitable for use when a programming mistake has been made. 239 * 240 * @param format printf-style format string. 241 */ 242 void 243 _dbus_warn (const char *format, 244 ...) 245 { 246 va_list args; 247 248 if (!warn_initted) 249 init_warnings (); 250 251 va_start (args, format); 252 #ifdef DBUS_ANDROID_LOG 253 LOG_PRI_VA(ANDROID_LOG_WARN, LOG_TAG, format, args); 254 #else 255 vfprintf (stderr, format, args); 256 #endif /* DBUS_ANDROID_LOG */ 257 va_end (args); 258 259 if (fatal_warnings) 260 { 261 fflush (stderr); 262 _dbus_abort (); 263 } 264 } 265 266 /** 267 * Prints a "critical" warning to stderr when an assertion fails; 268 * differs from _dbus_warn primarily in that it prefixes the pid and 269 * defaults to fatal. This should be used only when a programming 270 * error has been detected. (NOT for unavoidable errors that an app 271 * might handle - those should be returned as DBusError.) Calling this 272 * means "there is a bug" 273 */ 274 void 275 _dbus_warn_check_failed(const char *format, 276 ...) 277 { 278 va_list args; 279 280 if (!warn_initted) 281 init_warnings (); 282 283 fprintf (stderr, "process %lu: ", _dbus_getpid ()); 284 285 va_start (args, format); 286 #ifdef DBUS_ANDROID_LOG 287 LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, format, args); 288 #else 289 vfprintf (stderr, format, args); 290 #endif /* DBUS_ANDROID_LOG */ 291 va_end (args); 292 293 if (fatal_warnings_on_check_failed) 294 { 295 fflush (stderr); 296 _dbus_abort (); 297 } 298 } 299 300 #ifdef DBUS_ENABLE_VERBOSE_MODE 301 302 static dbus_bool_t verbose_initted = FALSE; 303 static dbus_bool_t verbose = TRUE; 304 305 /** Whether to show the current thread in verbose messages */ 306 #define PTHREAD_IN_VERBOSE 0 307 #if PTHREAD_IN_VERBOSE 308 #include <pthread.h> 309 #endif 310 311 static inline void 312 _dbus_verbose_init (void) 313 { 314 if (!verbose_initted) 315 { 316 #ifdef DBUS_ANDROID_LOG 317 /* Don't bother checking environment variable - just print the 318 verbose logs (can still be disabled with DBUS_ENABLE_VERBOSE_MODE) */ 319 verbose = TRUE; 320 #else 321 const char *p = _dbus_getenv ("DBUS_VERBOSE"); 322 verbose = p != NULL && *p == '1'; 323 #endif 324 verbose_initted = TRUE; 325 } 326 } 327 328 /** 329 * Implementation of dbus_is_verbose() macro if built with verbose logging 330 * enabled. 331 * @returns whether verbose logging is active. 332 */ 333 dbus_bool_t 334 _dbus_is_verbose_real (void) 335 { 336 _dbus_verbose_init (); 337 return verbose; 338 } 339 340 /** 341 * Prints a warning message to stderr 342 * if the user has enabled verbose mode. 343 * This is the real function implementation, 344 * use _dbus_verbose() macro in code. 345 * 346 * @param format printf-style format string. 347 */ 348 void 349 _dbus_verbose_real (const char *format, 350 ...) 351 { 352 va_list args; 353 static dbus_bool_t need_pid = TRUE; 354 int len; 355 356 /* things are written a bit oddly here so that 357 * in the non-verbose case we just have the one 358 * conditional and return immediately. 359 */ 360 if (!_dbus_is_verbose_real()) 361 return; 362 363 /* Print out pid before the line */ 364 if (need_pid) 365 { 366 #if PTHREAD_IN_VERBOSE 367 fprintf (stderr, "%lu: 0x%lx: ", _dbus_getpid (), pthread_self ()); 368 #else 369 fprintf (stderr, "%lu: ", _dbus_getpid ()); 370 #endif 371 } 372 373 374 /* Only print pid again if the next line is a new line */ 375 len = strlen (format); 376 if (format[len-1] == '\n') 377 need_pid = TRUE; 378 else 379 need_pid = FALSE; 380 381 va_start (args, format); 382 #ifdef DBUS_ANDROID_LOG 383 LOG_PRI_VA(ANDROID_LOG_DEBUG, LOG_TAG, format, args); 384 #else 385 vfprintf (stderr, format, args); 386 #endif /* DBUS_ANDROID_LOG */ 387 va_end (args); 388 389 fflush (stderr); 390 } 391 392 /** 393 * Reinitializes the verbose logging code, used 394 * as a hack in dbus-spawn.c so that a child 395 * process re-reads its pid 396 * 397 */ 398 void 399 _dbus_verbose_reset_real (void) 400 { 401 verbose_initted = FALSE; 402 } 403 404 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 405 406 /** 407 * Duplicates a string. Result must be freed with 408 * dbus_free(). Returns #NULL if memory allocation fails. 409 * If the string to be duplicated is #NULL, returns #NULL. 410 * 411 * @param str string to duplicate. 412 * @returns newly-allocated copy. 413 */ 414 char* 415 _dbus_strdup (const char *str) 416 { 417 size_t len; 418 char *copy; 419 420 if (str == NULL) 421 return NULL; 422 423 len = strlen (str); 424 425 copy = dbus_malloc (len + 1); 426 if (copy == NULL) 427 return NULL; 428 429 memcpy (copy, str, len + 1); 430 431 return copy; 432 } 433 434 /** 435 * Duplicates a block of memory. Returns 436 * #NULL on failure. 437 * 438 * @param mem memory to copy 439 * @param n_bytes number of bytes to copy 440 * @returns the copy 441 */ 442 void* 443 _dbus_memdup (const void *mem, 444 size_t n_bytes) 445 { 446 void *copy; 447 448 copy = dbus_malloc (n_bytes); 449 if (copy == NULL) 450 return NULL; 451 452 memcpy (copy, mem, n_bytes); 453 454 return copy; 455 } 456 457 /** 458 * Duplicates a string array. Result may be freed with 459 * dbus_free_string_array(). Returns #NULL if memory allocation fails. 460 * If the array to be duplicated is #NULL, returns #NULL. 461 * 462 * @param array array to duplicate. 463 * @returns newly-allocated copy. 464 */ 465 char** 466 _dbus_dup_string_array (const char **array) 467 { 468 int len; 469 int i; 470 char **copy; 471 472 if (array == NULL) 473 return NULL; 474 475 for (len = 0; array[len] != NULL; ++len) 476 ; 477 478 copy = dbus_new0 (char*, len + 1); 479 if (copy == NULL) 480 return NULL; 481 482 i = 0; 483 while (i < len) 484 { 485 copy[i] = _dbus_strdup (array[i]); 486 if (copy[i] == NULL) 487 { 488 dbus_free_string_array (copy); 489 return NULL; 490 } 491 492 ++i; 493 } 494 495 return copy; 496 } 497 498 /** 499 * Checks whether a string array contains the given string. 500 * 501 * @param array array to search. 502 * @param str string to look for 503 * @returns #TRUE if array contains string 504 */ 505 dbus_bool_t 506 _dbus_string_array_contains (const char **array, 507 const char *str) 508 { 509 int i; 510 511 i = 0; 512 while (array[i] != NULL) 513 { 514 if (strcmp (array[i], str) == 0) 515 return TRUE; 516 ++i; 517 } 518 519 return FALSE; 520 } 521 522 /** 523 * Generates a new UUID. If you change how this is done, 524 * there's some text about it in the spec that should also change. 525 * 526 * @param uuid the uuid to initialize 527 */ 528 void 529 _dbus_generate_uuid (DBusGUID *uuid) 530 { 531 long now; 532 533 _dbus_get_current_time (&now, NULL); 534 535 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now); 536 537 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4); 538 } 539 540 /** 541 * Hex-encode a UUID. 542 * 543 * @param uuid the uuid 544 * @param encoded string to append hex uuid to 545 * @returns #FALSE if no memory 546 */ 547 dbus_bool_t 548 _dbus_uuid_encode (const DBusGUID *uuid, 549 DBusString *encoded) 550 { 551 DBusString binary; 552 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); 553 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded)); 554 } 555 556 static dbus_bool_t 557 _dbus_read_uuid_file_without_creating (const DBusString *filename, 558 DBusGUID *uuid, 559 DBusError *error) 560 { 561 DBusString contents; 562 DBusString decoded; 563 int end; 564 565 _dbus_string_init (&contents); 566 _dbus_string_init (&decoded); 567 568 if (!_dbus_file_get_contents (&contents, filename, error)) 569 goto error; 570 571 _dbus_string_chop_white (&contents); 572 573 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX) 574 { 575 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, 576 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text", 577 _dbus_string_get_const_data (filename), 578 DBUS_UUID_LENGTH_HEX, 579 _dbus_string_get_length (&contents)); 580 goto error; 581 } 582 583 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0)) 584 { 585 _DBUS_SET_OOM (error); 586 goto error; 587 } 588 589 if (end == 0) 590 { 591 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, 592 "UUID file '%s' contains invalid hex data", 593 _dbus_string_get_const_data (filename)); 594 goto error; 595 } 596 597 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES) 598 { 599 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, 600 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d", 601 _dbus_string_get_const_data (filename), 602 _dbus_string_get_length (&decoded), 603 DBUS_UUID_LENGTH_BYTES); 604 goto error; 605 } 606 607 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); 608 609 _dbus_string_free (&decoded); 610 _dbus_string_free (&contents); 611 612 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 613 614 return TRUE; 615 616 error: 617 _DBUS_ASSERT_ERROR_IS_SET (error); 618 _dbus_string_free (&contents); 619 _dbus_string_free (&decoded); 620 return FALSE; 621 } 622 623 static dbus_bool_t 624 _dbus_create_uuid_file_exclusively (const DBusString *filename, 625 DBusGUID *uuid, 626 DBusError *error) 627 { 628 DBusString encoded; 629 630 _dbus_string_init (&encoded); 631 632 _dbus_generate_uuid (uuid); 633 634 if (!_dbus_uuid_encode (uuid, &encoded)) 635 { 636 _DBUS_SET_OOM (error); 637 goto error; 638 } 639 640 /* FIXME this is racy; we need a save_file_exclusively 641 * function. But in practice this should be fine for now. 642 * 643 * - first be sure we can create the file and it 644 * doesn't exist by creating it empty with O_EXCL 645 * - then create it by creating a temporary file and 646 * overwriting atomically with rename() 647 */ 648 if (!_dbus_create_file_exclusively (filename, error)) 649 goto error; 650 651 if (!_dbus_string_append_byte (&encoded, '\n')) 652 { 653 _DBUS_SET_OOM (error); 654 goto error; 655 } 656 657 if (!_dbus_string_save_to_file (&encoded, filename, error)) 658 goto error; 659 660 if (!_dbus_make_file_world_readable (filename, error)) 661 goto error; 662 663 _dbus_string_free (&encoded); 664 665 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 666 return TRUE; 667 668 error: 669 _DBUS_ASSERT_ERROR_IS_SET (error); 670 _dbus_string_free (&encoded); 671 return FALSE; 672 } 673 674 /** 675 * Reads (and optionally writes) a uuid to a file. Initializes the uuid 676 * unless an error is returned. 677 * 678 * @param filename the name of the file 679 * @param uuid uuid to be initialized with the loaded uuid 680 * @param create_if_not_found #TRUE to create a new uuid and save it if the file doesn't exist 681 * @param error the error return 682 * @returns #FALSE if the error is set 683 */ 684 dbus_bool_t 685 _dbus_read_uuid_file (const DBusString *filename, 686 DBusGUID *uuid, 687 dbus_bool_t create_if_not_found, 688 DBusError *error) 689 { 690 DBusError read_error; 691 692 dbus_error_init (&read_error); 693 694 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error)) 695 return TRUE; 696 697 if (!create_if_not_found) 698 { 699 dbus_move_error (&read_error, error); 700 return FALSE; 701 } 702 703 /* If the file exists and contains junk, we want to keep that error 704 * message instead of overwriting it with a "file exists" error 705 * message when we try to write 706 */ 707 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT)) 708 { 709 dbus_move_error (&read_error, error); 710 return FALSE; 711 } 712 else 713 { 714 dbus_error_free (&read_error); 715 return _dbus_create_uuid_file_exclusively (filename, uuid, error); 716 } 717 } 718 719 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid); 720 static int machine_uuid_initialized_generation = 0; 721 static DBusGUID machine_uuid; 722 723 /** 724 * Gets the hex-encoded UUID of the machine this function is 725 * executed on. This UUID is guaranteed to be the same for a given 726 * machine at least until it next reboots, though it also 727 * makes some effort to be the same forever, it may change if the 728 * machine is reconfigured or its hardware is modified. 729 * 730 * @param uuid_str string to append hex-encoded machine uuid to 731 * @returns #FALSE if no memory 732 */ 733 dbus_bool_t 734 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str) 735 { 736 dbus_bool_t ok; 737 738 _DBUS_LOCK (machine_uuid); 739 if (machine_uuid_initialized_generation != _dbus_current_generation) 740 { 741 DBusError error; 742 dbus_error_init (&error); 743 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE, 744 &error)) 745 { 746 #ifndef DBUS_BUILD_TESTS 747 /* For the test suite, we may not be installed so just continue silently 748 * here. But in a production build, we want to be nice and loud about 749 * this. 750 */ 751 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n" 752 "See the manual page for dbus-uuidgen to correct this issue.\n", 753 error.message); 754 #endif 755 756 dbus_error_free (&error); 757 758 _dbus_generate_uuid (&machine_uuid); 759 } 760 } 761 762 ok = _dbus_uuid_encode (&machine_uuid, uuid_str); 763 764 _DBUS_UNLOCK (machine_uuid); 765 766 return ok; 767 } 768 769 #ifdef DBUS_BUILD_TESTS 770 /** 771 * Returns a string describing the given name. 772 * 773 * @param header_field the field to describe 774 * @returns a constant string describing the field 775 */ 776 const char * 777 _dbus_header_field_to_string (int header_field) 778 { 779 switch (header_field) 780 { 781 case DBUS_HEADER_FIELD_INVALID: 782 return "invalid"; 783 case DBUS_HEADER_FIELD_PATH: 784 return "path"; 785 case DBUS_HEADER_FIELD_INTERFACE: 786 return "interface"; 787 case DBUS_HEADER_FIELD_MEMBER: 788 return "member"; 789 case DBUS_HEADER_FIELD_ERROR_NAME: 790 return "error-name"; 791 case DBUS_HEADER_FIELD_REPLY_SERIAL: 792 return "reply-serial"; 793 case DBUS_HEADER_FIELD_DESTINATION: 794 return "destination"; 795 case DBUS_HEADER_FIELD_SENDER: 796 return "sender"; 797 case DBUS_HEADER_FIELD_SIGNATURE: 798 return "signature"; 799 default: 800 return "unknown"; 801 } 802 } 803 #endif /* DBUS_BUILD_TESTS */ 804 805 #ifndef DBUS_DISABLE_CHECKS 806 /** String used in _dbus_return_if_fail macro */ 807 const char _dbus_return_if_fail_warning_format[] = 808 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n" 809 "This is normally a bug in some application using the D-Bus library.\n"; 810 #endif 811 812 #ifndef DBUS_DISABLE_ASSERT 813 /** 814 * Internals of _dbus_assert(); it's a function 815 * rather than a macro with the inline code so 816 * that the assertion failure blocks don't show up 817 * in test suite coverage, and to shrink code size. 818 * 819 * @param condition TRUE if assertion succeeded 820 * @param condition_text condition as a string 821 * @param file file the assertion is in 822 * @param line line the assertion is in 823 * @param func function the assertion is in 824 */ 825 void 826 _dbus_real_assert (dbus_bool_t condition, 827 const char *condition_text, 828 const char *file, 829 int line, 830 const char *func) 831 { 832 if (_DBUS_UNLIKELY (!condition)) 833 { 834 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n", 835 _dbus_getpid (), condition_text, file, line, func); 836 _dbus_abort (); 837 } 838 } 839 840 /** 841 * Internals of _dbus_assert_not_reached(); it's a function 842 * rather than a macro with the inline code so 843 * that the assertion failure blocks don't show up 844 * in test suite coverage, and to shrink code size. 845 * 846 * @param explanation what was reached that shouldn't have been 847 * @param file file the assertion is in 848 * @param line line the assertion is in 849 */ 850 void 851 _dbus_real_assert_not_reached (const char *explanation, 852 const char *file, 853 int line) 854 { 855 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n", 856 file, line, _dbus_getpid (), explanation); 857 _dbus_abort (); 858 } 859 #endif /* DBUS_DISABLE_ASSERT */ 860 861 #ifdef DBUS_BUILD_TESTS 862 static dbus_bool_t 863 run_failing_each_malloc (int n_mallocs, 864 const char *description, 865 DBusTestMemoryFunction func, 866 void *data) 867 { 868 n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */ 869 870 while (n_mallocs >= 0) 871 { 872 _dbus_set_fail_alloc_counter (n_mallocs); 873 874 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n", 875 description, n_mallocs, 876 _dbus_get_fail_alloc_failures ()); 877 878 if (!(* func) (data)) 879 return FALSE; 880 881 n_mallocs -= 1; 882 } 883 884 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); 885 886 return TRUE; 887 } 888 889 /** 890 * Tests how well the given function responds to out-of-memory 891 * situations. Calls the function repeatedly, failing a different 892 * call to malloc() each time. If the function ever returns #FALSE, 893 * the test fails. The function should return #TRUE whenever something 894 * valid (such as returning an error, or succeeding) occurs, and #FALSE 895 * if it gets confused in some way. 896 * 897 * @param description description of the test used in verbose output 898 * @param func function to call 899 * @param data data to pass to function 900 * @returns #TRUE if the function never returns FALSE 901 */ 902 dbus_bool_t 903 _dbus_test_oom_handling (const char *description, 904 DBusTestMemoryFunction func, 905 void *data) 906 { 907 int approx_mallocs; 908 const char *setting; 909 int max_failures_to_try; 910 int i; 911 912 /* Run once to see about how many mallocs are involved */ 913 914 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); 915 916 _dbus_verbose ("Running once to count mallocs\n"); 917 918 if (!(* func) (data)) 919 return FALSE; 920 921 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter (); 922 923 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n", 924 description, approx_mallocs); 925 926 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES"); 927 if (setting != NULL) 928 { 929 DBusString str; 930 long v; 931 _dbus_string_init_const (&str, setting); 932 v = 4; 933 if (!_dbus_string_parse_int (&str, 0, &v, NULL)) 934 _dbus_warn ("couldn't parse '%s' as integer\n", setting); 935 max_failures_to_try = v; 936 } 937 else 938 { 939 max_failures_to_try = 4; 940 } 941 942 i = setting ? max_failures_to_try - 1 : 1; 943 while (i < max_failures_to_try) 944 { 945 _dbus_set_fail_alloc_failures (i); 946 if (!run_failing_each_malloc (approx_mallocs, description, func, data)) 947 return FALSE; 948 ++i; 949 } 950 951 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n", 952 description); 953 954 return TRUE; 955 } 956 #endif /* DBUS_BUILD_TESTS */ 957 958 /** @} */ 959