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