D-Bus  1.10.12
dbus-internals.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-internals.c  random utility stuff (internal to D-Bus implementation)
00003  *
00004  * Copyright (C) 2002, 2003  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-marshal-basic.h"
00028 #include "dbus-test.h"
00029 #include "dbus-valgrind-internal.h"
00030 #include <stdio.h>
00031 #include <stdarg.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00035 #include <windows.h>
00036 #include <mbstring.h>
00037 #endif
00038 
00184 const char *_dbus_no_memory_message = "Not enough memory";
00185 
00186 static dbus_bool_t warn_initted = FALSE;
00187 static dbus_bool_t fatal_warnings = FALSE;
00188 static dbus_bool_t fatal_warnings_on_check_failed = TRUE;
00189 
00190 static void
00191 init_warnings(void)
00192 {
00193   if (!warn_initted)
00194     {
00195       const char *s;
00196       s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
00197       if (s && *s)
00198         {
00199           if (*s == '0')
00200             {
00201               fatal_warnings = FALSE;
00202               fatal_warnings_on_check_failed = FALSE;
00203             }
00204           else if (*s == '1')
00205             {
00206               fatal_warnings = TRUE;
00207               fatal_warnings_on_check_failed = TRUE;
00208             }
00209           else
00210             {
00211               fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
00212                       s);
00213             }
00214         }
00215 
00216       warn_initted = TRUE;
00217     }
00218 }
00219 
00229 void
00230 _dbus_warn (const char *format,
00231             ...)
00232 {
00233   va_list args;
00234 
00235   if (!warn_initted)
00236     init_warnings ();
00237   
00238   va_start (args, format);
00239   vfprintf (stderr, format, args);
00240   va_end (args);
00241 
00242   if (fatal_warnings)
00243     {
00244       fflush (stderr);
00245       _dbus_abort ();
00246     }
00247 }
00248 
00257 void
00258 _dbus_warn_check_failed(const char *format,
00259                         ...)
00260 {
00261   va_list args;
00262   
00263   if (!warn_initted)
00264     init_warnings ();
00265 
00266   fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());
00267   
00268   va_start (args, format);
00269   vfprintf (stderr, format, args);
00270   va_end (args);
00271 
00272   if (fatal_warnings_on_check_failed)
00273     {
00274       fflush (stderr);
00275       _dbus_abort ();
00276     }
00277 }
00278 
00279 #ifdef DBUS_ENABLE_VERBOSE_MODE
00280 
00281 static dbus_bool_t verbose_initted = FALSE;
00282 static dbus_bool_t verbose = TRUE;
00283 
00285 #define PTHREAD_IN_VERBOSE 0
00286 #if PTHREAD_IN_VERBOSE
00287 #include <pthread.h>
00288 #endif
00289 
00290 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00291 static char module_name[1024];
00292 #endif
00293 
00294 static inline void
00295 _dbus_verbose_init (void)
00296 {
00297   if (!verbose_initted)
00298     {
00299       const char *p = _dbus_getenv ("DBUS_VERBOSE");
00300       verbose = p != NULL && *p == '1';
00301       verbose_initted = TRUE;
00302 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00303       {
00304         char *last_period, *last_slash;
00305         GetModuleFileName(0,module_name,sizeof(module_name)-1);
00306         last_period = _mbsrchr(module_name,'.');
00307         if (last_period)
00308           *last_period ='\0';
00309         last_slash = _mbsrchr(module_name,'\\');
00310         if (last_slash)
00311           strcpy(module_name,last_slash+1);
00312         strcat(module_name,": ");
00313       }
00314 #endif
00315     }
00316 }
00317 
00323 #ifdef DBUS_WIN 
00324 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
00325 #else
00326 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
00327 #endif
00328 
00333 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
00334 {
00335   int prefix = 0;
00336   char *p = (char *)file + strlen(file);
00337   int i = 0;
00338 
00339   for (;p >= file;p--)
00340     {
00341       if (DBUS_IS_DIR_SEPARATOR(*p))
00342         {
00343           if (++i >= level)
00344             {
00345               prefix = p-file+1;
00346               break;
00347             }
00348        }
00349     }
00350 
00351   return (char *)file+prefix;
00352 }
00353 
00359 dbus_bool_t
00360 _dbus_is_verbose_real (void)
00361 {
00362   _dbus_verbose_init ();
00363   return verbose;
00364 }
00365 
00366 void _dbus_set_verbose (dbus_bool_t state)
00367 {
00368     verbose = state;
00369 }
00370 
00371 dbus_bool_t _dbus_get_verbose (void)
00372 {
00373     return verbose;
00374 }
00375 
00384 void
00385 _dbus_verbose_real (
00386 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00387                     const char *file,
00388                     const int line, 
00389                     const char *function, 
00390 #endif
00391                     const char *format,
00392                     ...)
00393 {
00394   va_list args;
00395   static dbus_bool_t need_pid = TRUE;
00396   int len;
00397   
00398   /* things are written a bit oddly here so that
00399    * in the non-verbose case we just have the one
00400    * conditional and return immediately.
00401    */
00402   if (!_dbus_is_verbose_real())
00403     return;
00404 
00405 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
00406   /* Print out pid before the line */
00407   if (need_pid)
00408     {
00409 #if PTHREAD_IN_VERBOSE
00410       fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00411 #else
00412       fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00413 #endif
00414     }
00415 #endif
00416 
00417   /* Only print pid again if the next line is a new line */
00418   len = strlen (format);
00419   if (format[len-1] == '\n')
00420     need_pid = TRUE;
00421   else
00422     need_pid = FALSE;
00423 
00424   va_start (args, format);
00425 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00426   {
00427   char buf[1024];
00428   strcpy(buf,module_name);
00429 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00430   sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00431 #endif
00432   vsprintf (buf+strlen(buf),format, args);
00433   va_end (args);
00434   OutputDebugStringA(buf);
00435   }
00436 #else
00437 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00438   fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00439 #endif
00440 
00441   vfprintf (stderr, format, args);
00442   va_end (args);
00443 
00444   fflush (stderr);
00445 #endif
00446 }
00447 
00454 void
00455 _dbus_verbose_reset_real (void)
00456 {
00457   verbose_initted = FALSE;
00458 }
00459 
00460 void
00461 _dbus_trace_ref (const char *obj_name,
00462                  void       *obj,
00463                  int         old_refcount,
00464                  int         new_refcount,
00465                  const char *why,
00466                  const char *env_var,
00467                  int        *enabled)
00468 {
00469   _dbus_assert (obj_name != NULL);
00470   _dbus_assert (obj != NULL);
00471   _dbus_assert (old_refcount >= -1);
00472   _dbus_assert (new_refcount >= -1);
00473 
00474   if (old_refcount == -1)
00475     {
00476       _dbus_assert (new_refcount == -1);
00477     }
00478   else
00479     {
00480       _dbus_assert (new_refcount >= 0);
00481       _dbus_assert (old_refcount >= 0);
00482       _dbus_assert (old_refcount > 0 || new_refcount > 0);
00483     }
00484 
00485   _dbus_assert (why != NULL);
00486   _dbus_assert (env_var != NULL);
00487   _dbus_assert (enabled != NULL);
00488 
00489   if (*enabled < 0)
00490     {
00491       const char *s = _dbus_getenv (env_var);
00492 
00493       *enabled = FALSE;
00494 
00495       if (s && *s)
00496         {
00497           if (*s == '0')
00498             *enabled = FALSE;
00499           else if (*s == '1')
00500             *enabled = TRUE;
00501           else
00502             _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
00503         }
00504     }
00505 
00506   if (*enabled)
00507     {
00508       if (old_refcount == -1)
00509         {
00510           VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
00511                                      obj_name, obj, why);
00512           _dbus_verbose ("%s %p ref stolen (%s)\n",
00513                          obj_name, obj, why);
00514         }
00515       else
00516         {
00517           VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
00518                                      obj_name, obj,
00519                                      old_refcount, new_refcount, why);
00520           _dbus_verbose ("%s %p %d -> %d refs (%s)\n",
00521                          obj_name, obj, old_refcount, new_refcount, why);
00522         }
00523     }
00524 }
00525 
00526 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00527 
00536 char*
00537 _dbus_strdup (const char *str)
00538 {
00539   size_t len;
00540   char *copy;
00541   
00542   if (str == NULL)
00543     return NULL;
00544   
00545   len = strlen (str);
00546 
00547   copy = dbus_malloc (len + 1);
00548   if (copy == NULL)
00549     return NULL;
00550 
00551   memcpy (copy, str, len + 1);
00552   
00553   return copy;
00554 }
00555 
00564 void*
00565 _dbus_memdup (const void  *mem,
00566               size_t       n_bytes)
00567 {
00568   void *copy;
00569 
00570   copy = dbus_malloc (n_bytes);
00571   if (copy == NULL)
00572     return NULL;
00573 
00574   memcpy (copy, mem, n_bytes);
00575   
00576   return copy;
00577 }
00578 
00587 char**
00588 _dbus_dup_string_array (const char **array)
00589 {
00590   int len;
00591   int i;
00592   char **copy;
00593   
00594   if (array == NULL)
00595     return NULL;
00596 
00597   for (len = 0; array[len] != NULL; ++len)
00598     ;
00599 
00600   copy = dbus_new0 (char*, len + 1);
00601   if (copy == NULL)
00602     return NULL;
00603 
00604   i = 0;
00605   while (i < len)
00606     {
00607       copy[i] = _dbus_strdup (array[i]);
00608       if (copy[i] == NULL)
00609         {
00610           dbus_free_string_array (copy);
00611           return NULL;
00612         }
00613 
00614       ++i;
00615     }
00616 
00617   return copy;
00618 }
00619 
00627 dbus_bool_t
00628 _dbus_string_array_contains (const char **array,
00629                              const char  *str)
00630 {
00631   int i;
00632 
00633   i = 0;
00634   while (array[i] != NULL)
00635     {
00636       if (strcmp (array[i], str) == 0)
00637         return TRUE;
00638       ++i;
00639     }
00640 
00641   return FALSE;
00642 }
00643 
00652 dbus_bool_t
00653 _dbus_generate_uuid (DBusGUID  *uuid,
00654                      DBusError *error)
00655 {
00656   DBusError rand_error;
00657   long now;
00658 
00659   dbus_error_init (&rand_error);
00660 
00661   /* don't use monotonic time because the UUID may be saved to disk, e.g.
00662    * it may persist across reboots
00663    */
00664   _dbus_get_real_time (&now, NULL);
00665 
00666   uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00667   
00668   if (!_dbus_generate_random_bytes_buffer (uuid->as_bytes,
00669                                            DBUS_UUID_LENGTH_BYTES - 4,
00670                                            &rand_error))
00671     {
00672       dbus_set_error (error, rand_error.name,
00673                       "Failed to generate UUID: %s", rand_error.message);
00674       dbus_error_free (&rand_error);
00675       return FALSE;
00676     }
00677 
00678   return TRUE;
00679 }
00680 
00688 dbus_bool_t
00689 _dbus_uuid_encode (const DBusGUID *uuid,
00690                    DBusString     *encoded)
00691 {
00692   DBusString binary;
00693   _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00694   return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00695 }
00696 
00697 static dbus_bool_t
00698 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00699                                        DBusGUID         *uuid,
00700                                        DBusError        *error)
00701 {
00702   DBusString contents;
00703   DBusString decoded;
00704   int end;
00705   
00706   if (!_dbus_string_init (&contents))
00707     {
00708       _DBUS_SET_OOM (error);
00709       return FALSE;
00710     }
00711 
00712   if (!_dbus_string_init (&decoded))
00713     {
00714       _dbus_string_free (&contents);
00715       _DBUS_SET_OOM (error);
00716       return FALSE;
00717     }
00718   
00719   if (!_dbus_file_get_contents (&contents, filename, error))
00720     goto error;
00721 
00722   _dbus_string_chop_white (&contents);
00723 
00724   if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00725     {
00726       dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00727                       "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00728                       _dbus_string_get_const_data (filename),
00729                       DBUS_UUID_LENGTH_HEX,
00730                       _dbus_string_get_length (&contents));
00731       goto error;
00732     }
00733 
00734   if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00735     {
00736       _DBUS_SET_OOM (error);
00737       goto error;
00738     }
00739 
00740   if (end == 0)
00741     {
00742       dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00743                       "UUID file '%s' contains invalid hex data",
00744                       _dbus_string_get_const_data (filename));
00745       goto error;
00746     }
00747 
00748   if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00749     {
00750       dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00751                       "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00752                       _dbus_string_get_const_data (filename),
00753                       _dbus_string_get_length (&decoded),
00754                       DBUS_UUID_LENGTH_BYTES);
00755       goto error;
00756     }
00757 
00758   _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00759 
00760   _dbus_string_free (&decoded);
00761   _dbus_string_free (&contents);
00762 
00763   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00764 
00765   return TRUE;
00766   
00767  error:
00768   _DBUS_ASSERT_ERROR_IS_SET (error);
00769   _dbus_string_free (&contents);
00770   _dbus_string_free (&decoded);
00771   return FALSE;
00772 }
00773 
00782 dbus_bool_t
00783 _dbus_write_uuid_file (const DBusString *filename,
00784                        const DBusGUID   *uuid,
00785                        DBusError        *error)
00786 {
00787   DBusString encoded;
00788 
00789   if (!_dbus_string_init (&encoded))
00790     {
00791       _DBUS_SET_OOM (error);
00792       return FALSE;
00793     }
00794   
00795   if (!_dbus_uuid_encode (uuid, &encoded))
00796     {
00797       _DBUS_SET_OOM (error);
00798       goto error;
00799     }
00800   
00801   if (!_dbus_string_append_byte (&encoded, '\n'))
00802     {
00803       _DBUS_SET_OOM (error);
00804       goto error;
00805     }
00806   
00807   if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
00808     goto error;
00809 
00810   _dbus_string_free (&encoded);
00811 
00812   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00813   return TRUE;
00814   
00815  error:
00816   _DBUS_ASSERT_ERROR_IS_SET (error);
00817   _dbus_string_free (&encoded);
00818   return FALSE;        
00819 }
00820 
00831 dbus_bool_t
00832 _dbus_read_uuid_file (const DBusString *filename,
00833                       DBusGUID         *uuid,
00834                       dbus_bool_t       create_if_not_found,
00835                       DBusError        *error)
00836 {
00837   DBusError read_error = DBUS_ERROR_INIT;
00838 
00839   if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00840     return TRUE;
00841 
00842   if (!create_if_not_found)
00843     {
00844       dbus_move_error (&read_error, error);
00845       return FALSE;
00846     }
00847 
00848   /* If the file exists and contains junk, we want to keep that error
00849    * message instead of overwriting it with a "file exists" error
00850    * message when we try to write
00851    */
00852   if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00853     {
00854       dbus_move_error (&read_error, error);
00855       return FALSE;
00856     }
00857   else
00858     {
00859       dbus_error_free (&read_error);
00860 
00861       if (!_dbus_generate_uuid (uuid, error))
00862         return FALSE;
00863 
00864       return _dbus_write_uuid_file (filename, uuid, error);
00865     }
00866 }
00867 
00868 /* Protected by _DBUS_LOCK (machine_uuid) */
00869 static int machine_uuid_initialized_generation = 0;
00870 static DBusGUID machine_uuid;
00871 
00883 dbus_bool_t
00884 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str,
00885                                       DBusError  *error)
00886 {
00887   dbus_bool_t ok = TRUE;
00888   
00889   if (!_DBUS_LOCK (machine_uuid))
00890     {
00891       _DBUS_SET_OOM (error);
00892       return FALSE;
00893     }
00894 
00895   if (machine_uuid_initialized_generation != _dbus_current_generation)
00896     {
00897       DBusError local_error = DBUS_ERROR_INIT;
00898 
00899       if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00900                                           &local_error))
00901         {          
00902 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
00903           /* For the test suite, we may not be installed so just continue silently
00904            * here. But in a production build, we want to be nice and loud about
00905            * this.
00906            */
00907           _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00908                                    "See the manual page for dbus-uuidgen to correct this issue.\n",
00909                                    local_error.message);
00910 #endif
00911           
00912           dbus_error_free (&local_error);
00913           
00914           ok = _dbus_generate_uuid (&machine_uuid, error);
00915         }
00916     }
00917 
00918   if (ok)
00919     {
00920       if (!_dbus_uuid_encode (&machine_uuid, uuid_str))
00921         {
00922           ok = FALSE;
00923           _DBUS_SET_OOM (error);
00924         }
00925     }
00926 
00927   _DBUS_UNLOCK (machine_uuid);
00928 
00929   return ok;
00930 }
00931 
00932 #ifndef DBUS_DISABLE_CHECKS
00933 
00934 const char *_dbus_return_if_fail_warning_format =
00935 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00936 "This is normally a bug in some application using the D-Bus library.\n";
00937 #endif
00938 
00939 #ifndef DBUS_DISABLE_ASSERT
00940 
00952 void
00953 _dbus_real_assert (dbus_bool_t  condition,
00954                    const char  *condition_text,
00955                    const char  *file,
00956                    int          line,
00957                    const char  *func)
00958 {
00959   if (_DBUS_UNLIKELY (!condition))
00960     {
00961       _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00962                   _dbus_pid_for_log (), condition_text, file, line, func);
00963       _dbus_abort ();
00964     }
00965 }
00966 
00977 void
00978 _dbus_real_assert_not_reached (const char *explanation,
00979                                const char *file,
00980                                int         line)
00981 {
00982   _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00983               file, line, _dbus_pid_for_log (), explanation);
00984   _dbus_abort ();
00985 }
00986 #endif /* DBUS_DISABLE_ASSERT */
00987   
00988 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00989 static dbus_bool_t
00990 run_failing_each_malloc (int                    n_mallocs,
00991                          const char            *description,
00992                          DBusTestMemoryFunction func,
00993                          void                  *data)
00994 {
00995   n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
00996   
00997   while (n_mallocs >= 0)
00998     {      
00999       _dbus_set_fail_alloc_counter (n_mallocs);
01000 
01001       _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
01002                      description, n_mallocs,
01003                      _dbus_get_fail_alloc_failures ());
01004 
01005       if (!(* func) (data))
01006         return FALSE;
01007       
01008       n_mallocs -= 1;
01009     }
01010 
01011   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
01012 
01013   return TRUE;
01014 }                        
01015 
01029 dbus_bool_t
01030 _dbus_test_oom_handling (const char             *description,
01031                          DBusTestMemoryFunction  func,
01032                          void                   *data)
01033 {
01034   int approx_mallocs;
01035   const char *setting;
01036   int max_failures_to_try;
01037   int i;
01038 
01039   /* Run once to see about how many mallocs are involved */
01040   
01041   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
01042 
01043   _dbus_verbose ("Running once to count mallocs\n");
01044   
01045   if (!(* func) (data))
01046     return FALSE;
01047   
01048   approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
01049 
01050   _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
01051                  description, approx_mallocs);
01052 
01053   setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
01054   if (setting != NULL)
01055     {
01056       DBusString str;
01057       long v;
01058       _dbus_string_init_const (&str, setting);
01059       v = 4;
01060       if (!_dbus_string_parse_int (&str, 0, &v, NULL))
01061         _dbus_warn ("couldn't parse '%s' as integer\n", setting);
01062       max_failures_to_try = v;
01063     }
01064   else
01065     {
01066       max_failures_to_try = 4;
01067     }
01068 
01069   if (max_failures_to_try < 1)
01070     {
01071       _dbus_verbose ("not testing OOM handling\n");
01072       return TRUE;
01073     }
01074 
01075   i = setting ? max_failures_to_try - 1 : 1;
01076   while (i < max_failures_to_try)
01077     {
01078       _dbus_set_fail_alloc_failures (i);
01079       if (!run_failing_each_malloc (approx_mallocs, description, func, data))
01080         return FALSE;
01081       ++i;
01082     }
01083   
01084   _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
01085                  description);
01086 
01087   return TRUE;
01088 }
01089 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
01090