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