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