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