dbus-internals.c revision a1df3040f29223eddaa3ace0fe018fcb28cddcd9
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.0 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-test.h" 26#include <stdio.h> 27#include <stdarg.h> 28#include <string.h> 29#include <sys/types.h> 30#include <errno.h> 31#include <unistd.h> 32#include <fcntl.h> 33#include <stdlib.h> 34 35/** 36 * @defgroup DBusInternals D-BUS 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_INT_MIN 102 * 103 * Minimum value of type "int" 104 */ 105/** 106 * @def _DBUS_INT_MAX 107 * 108 * Maximum value of type "int" 109 */ 110 111/** 112 * @typedef DBusForeachFunction 113 * 114 * Used to iterate over each item in a collection, such as 115 * a DBusList. 116 */ 117 118/** 119 * @def _DBUS_LOCK_NAME 120 * 121 * Expands to name of a global lock variable. 122 */ 123 124/** 125 * @def _DBUS_DEFINE_GLOBAL_LOCK 126 * 127 * Defines a global lock variable with the given name. 128 * The lock must be added to the list to initialize 129 * in dbus_threads_init(). 130 */ 131 132/** 133 * @def _DBUS_DECLARE_GLOBAL_LOCK 134 * 135 * Expands to declaration of a global lock defined 136 * with _DBUS_DEFINE_GLOBAL_LOCK. 137 * The lock must be added to the list to initialize 138 * in dbus_threads_init(). 139 */ 140 141/** 142 * @def _DBUS_LOCK 143 * 144 * Locks a global lock 145 */ 146 147/** 148 * @def _DBUS_UNLOCK 149 * 150 * Unlocks a global lock 151 */ 152 153/** 154 * Fixed "out of memory" error message, just to avoid 155 * making up a different string every time and wasting 156 * space. 157 */ 158const char _dbus_no_memory_message[] = "Not enough memory"; 159 160/** 161 * Prints a warning message to stderr. 162 * 163 * @param format printf-style format string. 164 */ 165void 166_dbus_warn (const char *format, 167 ...) 168{ 169 /* FIXME not portable enough? */ 170 va_list args; 171 172 va_start (args, format); 173 vfprintf (stderr, format, args); 174 va_end (args); 175} 176 177static dbus_bool_t verbose_initted = FALSE; 178 179/** 180 * Prints a warning message to stderr 181 * if the user has enabled verbose mode. 182 * This is the real function implementation, 183 * use _dbus_verbose() macro in code. 184 * 185 * @param format printf-style format string. 186 */ 187void 188_dbus_verbose_real (const char *format, 189 ...) 190{ 191 va_list args; 192 static dbus_bool_t verbose = TRUE; 193 static dbus_bool_t need_pid = TRUE; 194 195 /* things are written a bit oddly here so that 196 * in the non-verbose case we just have the one 197 * conditional and return immediately. 198 */ 199 if (!verbose) 200 return; 201 202 if (!verbose_initted) 203 { 204 verbose = _dbus_getenv ("DBUS_VERBOSE") != NULL; 205 verbose_initted = TRUE; 206 if (!verbose) 207 return; 208 } 209 210 if (need_pid) 211 { 212 int len; 213 214 fprintf (stderr, "%lu: ", _dbus_getpid ()); 215 216 len = strlen (format); 217 if (format[len-1] == '\n') 218 need_pid = TRUE; 219 else 220 need_pid = FALSE; 221 } 222 223 va_start (args, format); 224 vfprintf (stderr, format, args); 225 va_end (args); 226 227 fflush (stderr); 228} 229 230/** 231 * Reinitializes the verbose logging code, used 232 * as a hack in dbus-spawn.c so that a child 233 * process re-reads its pid 234 * 235 */ 236void 237_dbus_verbose_reset_real (void) 238{ 239 verbose_initted = FALSE; 240} 241 242/** 243 * Duplicates a string. Result must be freed with 244 * dbus_free(). Returns #NULL if memory allocation fails. 245 * If the string to be duplicated is #NULL, returns #NULL. 246 * 247 * @param str string to duplicate. 248 * @returns newly-allocated copy. 249 */ 250char* 251_dbus_strdup (const char *str) 252{ 253 size_t len; 254 char *copy; 255 256 if (str == NULL) 257 return NULL; 258 259 len = strlen (str); 260 261 copy = dbus_malloc (len + 1); 262 if (copy == NULL) 263 return NULL; 264 265 memcpy (copy, str, len + 1); 266 267 return copy; 268} 269 270/** 271 * Duplicates a block of memory. Returns 272 * #NULL on failure. 273 * 274 * @param mem memory to copy 275 * @param n_bytes number of bytes to copy 276 * @returns the copy 277 */ 278void* 279_dbus_memdup (const void *mem, 280 size_t n_bytes) 281{ 282 void *copy; 283 284 copy = dbus_malloc (n_bytes); 285 if (copy == NULL) 286 return NULL; 287 288 memcpy (copy, mem, n_bytes); 289 290 return copy; 291} 292 293/** 294 * Duplicates a string array. Result may be freed with 295 * dbus_free_string_array(). Returns #NULL if memory allocation fails. 296 * If the array to be duplicated is #NULL, returns #NULL. 297 * 298 * @param array array to duplicate. 299 * @returns newly-allocated copy. 300 */ 301char** 302_dbus_dup_string_array (const char **array) 303{ 304 int len; 305 int i; 306 char **copy; 307 308 if (array == NULL) 309 return NULL; 310 311 for (len = 0; array[len] != NULL; ++len) 312 ; 313 314 copy = dbus_new0 (char*, len + 1); 315 if (copy == NULL) 316 return NULL; 317 318 i = 0; 319 while (i < len) 320 { 321 copy[i] = _dbus_strdup (array[i]); 322 if (copy[i] == NULL) 323 { 324 dbus_free_string_array (copy); 325 return NULL; 326 } 327 328 ++i; 329 } 330 331 return copy; 332} 333 334/** 335 * Checks whether a string array contains the given string. 336 * 337 * @param array array to search. 338 * @param str string to look for 339 * @returns #TRUE if array contains string 340 */ 341dbus_bool_t 342_dbus_string_array_contains (const char **array, 343 const char *str) 344{ 345 int i; 346 347 i = 0; 348 while (array[i] != NULL) 349 { 350 if (strcmp (array[i], str) == 0) 351 return TRUE; 352 ++i; 353 } 354 355 return FALSE; 356} 357 358/** 359 * Returns a string describing the given type. 360 * 361 * @param type the type to describe 362 * @returns a constant string describing the type 363 */ 364const char * 365_dbus_type_to_string (int type) 366{ 367 switch (type) 368 { 369 case DBUS_TYPE_INVALID: 370 return "invalid"; 371 case DBUS_TYPE_NIL: 372 return "nil"; 373 case DBUS_TYPE_BOOLEAN: 374 return "boolean"; 375 case DBUS_TYPE_INT32: 376 return "int32"; 377 case DBUS_TYPE_UINT32: 378 return "uint32"; 379 case DBUS_TYPE_DOUBLE: 380 return "double"; 381 case DBUS_TYPE_STRING: 382 return "string"; 383 case DBUS_TYPE_CUSTOM: 384 return "custom"; 385 case DBUS_TYPE_ARRAY: 386 return "array"; 387 case DBUS_TYPE_DICT: 388 return "dict"; 389 default: 390 return "unknown"; 391 } 392} 393 394/** 395 * Returns a string describing the given name. 396 * 397 * @param header_field the field to describe 398 * @returns a constant string describing the field 399 */ 400const char * 401_dbus_header_field_to_string (int header_field) 402{ 403 switch (header_field) 404 { 405 case DBUS_HEADER_FIELD_INVALID: 406 return "invalid"; 407 case DBUS_HEADER_FIELD_PATH: 408 return "path"; 409 case DBUS_HEADER_FIELD_INTERFACE: 410 return "interface"; 411 case DBUS_HEADER_FIELD_MEMBER: 412 return "member"; 413 case DBUS_HEADER_FIELD_ERROR_NAME: 414 return "error-name"; 415 case DBUS_HEADER_FIELD_REPLY_SERIAL: 416 return "reply-serial"; 417 case DBUS_HEADER_FIELD_SERVICE: 418 return "service"; 419 case DBUS_HEADER_FIELD_SENDER_SERVICE: 420 return "sender-service"; 421 default: 422 return "unknown"; 423 } 424} 425 426#ifndef DBUS_DISABLE_CHECKS 427/** String used in _dbus_return_if_fail macro */ 428const char _dbus_return_if_fail_warning_format[] = 429"%lu: arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n" 430"This is normally a bug in some application using the D-BUS library.\n"; 431#endif 432 433#ifndef DBUS_DISABLE_ASSERT 434/** 435 * Internals of _dbus_assert(); it's a function 436 * rather than a macro with the inline code so 437 * that the assertion failure blocks don't show up 438 * in test suite coverage, and to shrink code size. 439 * 440 * @param condition TRUE if assertion succeeded 441 * @param condition_text condition as a string 442 * @param file file the assertion is in 443 * @param line line the assertion is in 444 */ 445void 446_dbus_real_assert (dbus_bool_t condition, 447 const char *condition_text, 448 const char *file, 449 int line) 450{ 451 if (_DBUS_UNLIKELY (!condition)) 452 { 453 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d\n", 454 _dbus_getpid (), condition_text, file, line); 455 _dbus_abort (); 456 } 457} 458 459/** 460 * Internals of _dbus_assert_not_reached(); it's a function 461 * rather than a macro with the inline code so 462 * that the assertion failure blocks don't show up 463 * in test suite coverage, and to shrink code size. 464 * 465 * @param explanation what was reached that shouldn't have been 466 * @param file file the assertion is in 467 * @param line line the assertion is in 468 */ 469void 470_dbus_real_assert_not_reached (const char *explanation, 471 const char *file, 472 int line) 473{ 474 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n", 475 file, line, _dbus_getpid (), explanation); 476 _dbus_abort (); 477} 478#endif /* DBUS_DISABLE_ASSERT */ 479 480#ifdef DBUS_BUILD_TESTS 481static dbus_bool_t 482run_failing_each_malloc (int n_mallocs, 483 const char *description, 484 DBusTestMemoryFunction func, 485 void *data) 486{ 487 n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */ 488 489 while (n_mallocs >= 0) 490 { 491 _dbus_set_fail_alloc_counter (n_mallocs); 492 493 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n", 494 description, n_mallocs, 495 _dbus_get_fail_alloc_failures ()); 496 497 if (!(* func) (data)) 498 return FALSE; 499 500 n_mallocs -= 1; 501 } 502 503 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); 504 505 return TRUE; 506} 507 508/** 509 * Tests how well the given function responds to out-of-memory 510 * situations. Calls the function repeatedly, failing a different 511 * call to malloc() each time. If the function ever returns #FALSE, 512 * the test fails. The function should return #TRUE whenever something 513 * valid (such as returning an error, or succeeding) occurs, and #FALSE 514 * if it gets confused in some way. 515 * 516 * @param description description of the test used in verbose output 517 * @param func function to call 518 * @param data data to pass to function 519 * @returns #TRUE if the function never returns FALSE 520 */ 521dbus_bool_t 522_dbus_test_oom_handling (const char *description, 523 DBusTestMemoryFunction func, 524 void *data) 525{ 526 int approx_mallocs; 527 528 /* Run once to see about how many mallocs are involved */ 529 530 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); 531 532 _dbus_verbose ("Running once to count mallocs\n"); 533 534 if (!(* func) (data)) 535 return FALSE; 536 537 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter (); 538 539 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n", 540 description, approx_mallocs); 541 542 _dbus_set_fail_alloc_failures (1); 543 if (!run_failing_each_malloc (approx_mallocs, description, func, data)) 544 return FALSE; 545 546 _dbus_set_fail_alloc_failures (2); 547 if (!run_failing_each_malloc (approx_mallocs, description, func, data)) 548 return FALSE; 549 550 _dbus_set_fail_alloc_failures (3); 551 if (!run_failing_each_malloc (approx_mallocs, description, func, data)) 552 return FALSE; 553 554 _dbus_set_fail_alloc_failures (4); 555 if (!run_failing_each_malloc (approx_mallocs, description, func, data)) 556 return FALSE; 557 558 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n", 559 description); 560 561 return TRUE; 562} 563#endif /* DBUS_BUILD_TESTS */ 564 565/** @} */ 566