• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
init_warnings(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
_dbus_warn(const char * format,...)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
_dbus_warn_check_failed(const char * format,...)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
_dbus_verbose_init(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
_dbus_is_verbose_real(void)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
_dbus_verbose_real(const char * format,...)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
_dbus_verbose_reset_real(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*
_dbus_strdup(const char * str)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*
_dbus_memdup(const void * mem,size_t n_bytes)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**
_dbus_dup_string_array(const char ** array)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
_dbus_string_array_contains(const char ** array,const char * str)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
_dbus_generate_uuid(DBusGUID * uuid)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
_dbus_uuid_encode(const DBusGUID * uuid,DBusString * encoded)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
_dbus_read_uuid_file_without_creating(const DBusString * filename,DBusGUID * uuid,DBusError * error)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
_dbus_create_uuid_file_exclusively(const DBusString * filename,DBusGUID * uuid,DBusError * error)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
_dbus_read_uuid_file(const DBusString * filename,DBusGUID * uuid,dbus_bool_t create_if_not_found,DBusError * error)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
_dbus_get_local_machine_uuid_encoded(DBusString * uuid_str)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 *
_dbus_header_field_to_string(int header_field)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
_dbus_real_assert(dbus_bool_t condition,const char * condition_text,const char * file,int line,const char * func)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
_dbus_real_assert_not_reached(const char * explanation,const char * file,int line)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
run_failing_each_malloc(int n_mallocs,const char * description,DBusTestMemoryFunction func,void * data)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
_dbus_test_oom_handling(const char * description,DBusTestMemoryFunction func,void * data)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