Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* dbus-memory.c  D-Bus memory handling
      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-memory.h"
     26 #include "dbus-internals.h"
     27 #include "dbus-sysdeps.h"
     28 #include "dbus-list.h"
     29 #include <stdlib.h>
     30 
     31 /**
     32  * @defgroup DBusMemory Memory Allocation
     33  * @ingroup  DBus
     34  * @brief dbus_malloc(), dbus_free(), etc.
     35  *
     36  * Functions and macros related to allocating and releasing
     37  * blocks of memory.
     38  *
     39  */
     40 
     41 /**
     42  * @defgroup DBusMemoryInternals Memory allocation implementation details
     43  * @ingroup  DBusInternals
     44  * @brief internals of dbus_malloc() etc.
     45  *
     46  * Implementation details related to allocating and releasing blocks
     47  * of memory.
     48  */
     49 
     50 /**
     51  * @addtogroup DBusMemory
     52  *
     53  * @{
     54  */
     55 
     56 /**
     57  * @def dbus_new
     58  *
     59  * Safe macro for using dbus_malloc(). Accepts the type
     60  * to allocate and the number of type instances to
     61  * allocate as arguments, and returns a memory block
     62  * cast to the desired type, instead of as a void*.
     63  *
     64  * @param type type name to allocate
     65  * @param count number of instances in the allocated array
     66  * @returns the new memory block or #NULL on failure
     67  */
     68 
     69 /**
     70  * @def dbus_new0
     71  *
     72  * Safe macro for using dbus_malloc0(). Accepts the type
     73  * to allocate and the number of type instances to
     74  * allocate as arguments, and returns a memory block
     75  * cast to the desired type, instead of as a void*.
     76  * The allocated array is initialized to all-bits-zero.
     77  *
     78  * @param type type name to allocate
     79  * @param count number of instances in the allocated array
     80  * @returns the new memory block or #NULL on failure
     81  */
     82 
     83 /**
     84  * @typedef DBusFreeFunction
     85  *
     86  * The type of a function which frees a block of memory.
     87  *
     88  * @param memory the memory to free
     89  */
     90 
     91 /** @} */ /* end of public API docs */
     92 
     93 /**
     94  * @addtogroup DBusMemoryInternals
     95  *
     96  * @{
     97  */
     98 
     99 #ifdef DBUS_BUILD_TESTS
    100 static dbus_bool_t debug_initialized = FALSE;
    101 static int fail_nth = -1;
    102 static size_t fail_size = 0;
    103 static int fail_alloc_counter = _DBUS_INT_MAX;
    104 static int n_failures_per_failure = 1;
    105 static int n_failures_this_failure = 0;
    106 static dbus_bool_t guards = FALSE;
    107 static dbus_bool_t disable_mem_pools = FALSE;
    108 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
    109 static dbus_bool_t malloc_cannot_fail = FALSE;
    110 static DBusAtomic n_blocks_outstanding = {0};
    111 
    112 /** value stored in guard padding for debugging buffer overrun */
    113 #define GUARD_VALUE 0xdeadbeef
    114 /** size of the information about the block stored in guard mode */
    115 #define GUARD_INFO_SIZE 8
    116 /** size of the GUARD_VALUE-filled padding after the header info  */
    117 #define GUARD_START_PAD 16
    118 /** size of the GUARD_VALUE-filled padding at the end of the block */
    119 #define GUARD_END_PAD 16
    120 /** size of stuff at start of block */
    121 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
    122 /** total extra size over the requested allocation for guard stuff */
    123 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
    124 
    125 static void
    126 _dbus_initialize_malloc_debug (void)
    127 {
    128   if (!debug_initialized)
    129     {
    130       debug_initialized = TRUE;
    131 
    132       if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
    133 	{
    134 	  fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
    135           fail_alloc_counter = fail_nth;
    136           _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth);
    137 	}
    138 
    139       if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
    140         {
    141           fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
    142           _dbus_verbose ("Will fail mallocs over %ld bytes\n",
    143                          (long) fail_size);
    144         }
    145 
    146       if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
    147         {
    148           guards = TRUE;
    149           _dbus_verbose ("Will use dbus_malloc guards\n");
    150         }
    151 
    152       if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
    153         {
    154           disable_mem_pools = TRUE;
    155           _dbus_verbose ("Will disable memory pools\n");
    156         }
    157 
    158       if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
    159         {
    160           backtrace_on_fail_alloc = TRUE;
    161           _dbus_verbose ("Will backtrace on failing a dbus_malloc\n");
    162         }
    163 
    164       if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL)
    165         {
    166           malloc_cannot_fail = TRUE;
    167           _dbus_verbose ("Will abort if system malloc() and friends fail\n");
    168         }
    169     }
    170 }
    171 
    172 /**
    173  * Whether to turn off mem pools, useful for leak checking.
    174  *
    175  * @returns #TRUE if mempools should not be used.
    176  */
    177 dbus_bool_t
    178 _dbus_disable_mem_pools (void)
    179 {
    180   _dbus_initialize_malloc_debug ();
    181   return disable_mem_pools;
    182 }
    183 
    184 /**
    185  * Sets the number of allocations until we simulate a failed
    186  * allocation. If set to 0, the next allocation to run
    187  * fails; if set to 1, one succeeds then the next fails; etc.
    188  * Set to _DBUS_INT_MAX to not fail anything.
    189  *
    190  * @param until_next_fail number of successful allocs before one fails
    191  */
    192 void
    193 _dbus_set_fail_alloc_counter (int until_next_fail)
    194 {
    195   _dbus_initialize_malloc_debug ();
    196 
    197   fail_alloc_counter = until_next_fail;
    198 
    199 #if 0
    200   _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
    201 #endif
    202 }
    203 
    204 /**
    205  * Gets the number of successful allocs until we'll simulate
    206  * a failed alloc.
    207  *
    208  * @returns current counter value
    209  */
    210 int
    211 _dbus_get_fail_alloc_counter (void)
    212 {
    213   _dbus_initialize_malloc_debug ();
    214 
    215   return fail_alloc_counter;
    216 }
    217 
    218 /**
    219  * Sets how many mallocs to fail when the fail alloc counter reaches
    220  * 0.
    221  *
    222  * @param failures_per_failure number to fail
    223  */
    224 void
    225 _dbus_set_fail_alloc_failures (int failures_per_failure)
    226 {
    227   n_failures_per_failure = failures_per_failure;
    228 }
    229 
    230 /**
    231  * Gets the number of failures we'll have when the fail malloc
    232  * counter reaches 0.
    233  *
    234  * @returns number of failures planned
    235  */
    236 int
    237 _dbus_get_fail_alloc_failures (void)
    238 {
    239   return n_failures_per_failure;
    240 }
    241 
    242 #ifdef DBUS_BUILD_TESTS
    243 /**
    244  * Called when about to alloc some memory; if
    245  * it returns #TRUE, then the allocation should
    246  * fail. If it returns #FALSE, then the allocation
    247  * should not fail.
    248  *
    249  * @returns #TRUE if this alloc should fail
    250  */
    251 dbus_bool_t
    252 _dbus_decrement_fail_alloc_counter (void)
    253 {
    254   _dbus_initialize_malloc_debug ();
    255 #ifdef DBUS_WIN_FIXME
    256   {
    257     static dbus_bool_t called = 0;
    258 
    259     if (!called)
    260       {
    261         _dbus_verbose("TODO: memory allocation testing errors disabled for now\n");
    262         called = 1;
    263       }
    264     return FALSE;
    265   }
    266 #endif
    267 
    268   if (fail_alloc_counter <= 0)
    269     {
    270       if (backtrace_on_fail_alloc)
    271         _dbus_print_backtrace ();
    272 
    273       _dbus_verbose ("failure %d\n", n_failures_this_failure);
    274 
    275       n_failures_this_failure += 1;
    276       if (n_failures_this_failure >= n_failures_per_failure)
    277         {
    278           if (fail_nth >= 0)
    279             fail_alloc_counter = fail_nth;
    280           else
    281             fail_alloc_counter = _DBUS_INT_MAX;
    282 
    283           n_failures_this_failure = 0;
    284 
    285           _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
    286         }
    287 
    288       return TRUE;
    289     }
    290   else
    291     {
    292       fail_alloc_counter -= 1;
    293       return FALSE;
    294     }
    295 }
    296 #endif /* DBUS_BUILD_TESTS */
    297 
    298 /**
    299  * Get the number of outstanding malloc()'d blocks.
    300  *
    301  * @returns number of blocks
    302  */
    303 int
    304 _dbus_get_malloc_blocks_outstanding (void)
    305 {
    306   return _dbus_atomic_get (&n_blocks_outstanding);
    307 }
    308 
    309 /**
    310  * Where the block came from.
    311  */
    312 typedef enum
    313 {
    314   SOURCE_UNKNOWN,
    315   SOURCE_MALLOC,
    316   SOURCE_REALLOC,
    317   SOURCE_MALLOC_ZERO,
    318   SOURCE_REALLOC_NULL
    319 } BlockSource;
    320 
    321 static const char*
    322 source_string (BlockSource source)
    323 {
    324   switch (source)
    325     {
    326     case SOURCE_UNKNOWN:
    327       return "unknown";
    328     case SOURCE_MALLOC:
    329       return "malloc";
    330     case SOURCE_REALLOC:
    331       return "realloc";
    332     case SOURCE_MALLOC_ZERO:
    333       return "malloc0";
    334     case SOURCE_REALLOC_NULL:
    335       return "realloc(NULL)";
    336     }
    337   _dbus_assert_not_reached ("Invalid malloc block source ID");
    338   return "invalid!";
    339 }
    340 
    341 static void
    342 check_guards (void       *free_block,
    343               dbus_bool_t overwrite)
    344 {
    345   if (free_block != NULL)
    346     {
    347       unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
    348       size_t requested_bytes = *(dbus_uint32_t*)block;
    349       BlockSource source = *(dbus_uint32_t*)(block + 4);
    350       unsigned int i;
    351       dbus_bool_t failed;
    352 
    353       failed = FALSE;
    354 
    355 #if 0
    356       _dbus_verbose ("Checking %d bytes request from source %s\n",
    357                      requested_bytes, source_string (source));
    358 #endif
    359 
    360       i = GUARD_INFO_SIZE;
    361       while (i < GUARD_START_OFFSET)
    362         {
    363           dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
    364           if (value != GUARD_VALUE)
    365             {
    366               _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
    367                           (long) requested_bytes, source_string (source),
    368                           value, i, GUARD_VALUE);
    369               failed = TRUE;
    370             }
    371 
    372           i += 4;
    373         }
    374 
    375       i = GUARD_START_OFFSET + requested_bytes;
    376       while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
    377         {
    378           dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
    379           if (value != GUARD_VALUE)
    380             {
    381               _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
    382                           (long) requested_bytes, source_string (source),
    383                           value, i, GUARD_VALUE);
    384               failed = TRUE;
    385             }
    386 
    387           i += 4;
    388         }
    389 
    390       /* set memory to anything but nul bytes */
    391       if (overwrite)
    392         memset (free_block, 'g', requested_bytes);
    393 
    394       if (failed)
    395         _dbus_assert_not_reached ("guard value corruption");
    396     }
    397 }
    398 
    399 static void*
    400 set_guards (void       *real_block,
    401             size_t      requested_bytes,
    402             BlockSource source)
    403 {
    404   unsigned char *block = real_block;
    405   unsigned int i;
    406 
    407   if (block == NULL)
    408     return NULL;
    409 
    410   _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
    411 
    412   *((dbus_uint32_t*)block) = requested_bytes;
    413   *((dbus_uint32_t*)(block + 4)) = source;
    414 
    415   i = GUARD_INFO_SIZE;
    416   while (i < GUARD_START_OFFSET)
    417     {
    418       (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
    419 
    420       i += 4;
    421     }
    422 
    423   i = GUARD_START_OFFSET + requested_bytes;
    424   while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
    425     {
    426       (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
    427 
    428       i += 4;
    429     }
    430 
    431   check_guards (block + GUARD_START_OFFSET, FALSE);
    432 
    433   return block + GUARD_START_OFFSET;
    434 }
    435 
    436 #endif
    437 
    438 /** @} */ /* End of internals docs */
    439 
    440 
    441 /**
    442  * @addtogroup DBusMemory
    443  *
    444  * @{
    445  */
    446 
    447 /**
    448  * Allocates the given number of bytes, as with standard
    449  * malloc(). Guaranteed to return #NULL if bytes is zero
    450  * on all platforms. Returns #NULL if the allocation fails.
    451  * The memory must be released with dbus_free().
    452  *
    453  * dbus_malloc() memory is NOT safe to free with regular free() from
    454  * the C library. Free it with dbus_free() only.
    455  *
    456  * @param bytes number of bytes to allocate
    457  * @return allocated memory, or #NULL if the allocation fails.
    458  */
    459 void*
    460 dbus_malloc (size_t bytes)
    461 {
    462 #ifdef DBUS_BUILD_TESTS
    463   _dbus_initialize_malloc_debug ();
    464 
    465   if (_dbus_decrement_fail_alloc_counter ())
    466     {
    467       _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
    468       return NULL;
    469     }
    470 #endif
    471 
    472   if (bytes == 0) /* some system mallocs handle this, some don't */
    473     return NULL;
    474 #ifdef DBUS_BUILD_TESTS
    475   else if (fail_size != 0 && bytes > fail_size)
    476     return NULL;
    477   else if (guards)
    478     {
    479       void *block;
    480 
    481       block = malloc (bytes + GUARD_EXTRA_SIZE);
    482       if (block)
    483         {
    484           _dbus_atomic_inc (&n_blocks_outstanding);
    485         }
    486       else if (malloc_cannot_fail)
    487         {
    488           _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
    489               (long) bytes, (long) GUARD_EXTRA_SIZE);
    490           _dbus_abort ();
    491         }
    492 
    493       return set_guards (block, bytes, SOURCE_MALLOC);
    494     }
    495 #endif
    496   else
    497     {
    498       void *mem;
    499       mem = malloc (bytes);
    500 
    501 #ifdef DBUS_BUILD_TESTS
    502       if (mem)
    503         {
    504           _dbus_atomic_inc (&n_blocks_outstanding);
    505         }
    506       else if (malloc_cannot_fail)
    507         {
    508           _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
    509           _dbus_abort ();
    510         }
    511 #endif
    512 
    513       return mem;
    514     }
    515 }
    516 
    517 /**
    518  * Allocates the given number of bytes, as with standard malloc(), but
    519  * all bytes are initialized to zero as with calloc(). Guaranteed to
    520  * return #NULL if bytes is zero on all platforms. Returns #NULL if the
    521  * allocation fails.  The memory must be released with dbus_free().
    522  *
    523  * dbus_malloc0() memory is NOT safe to free with regular free() from
    524  * the C library. Free it with dbus_free() only.
    525  *
    526  * @param bytes number of bytes to allocate
    527  * @return allocated memory, or #NULL if the allocation fails.
    528  */
    529 void*
    530 dbus_malloc0 (size_t bytes)
    531 {
    532 #ifdef DBUS_BUILD_TESTS
    533   _dbus_initialize_malloc_debug ();
    534 
    535   if (_dbus_decrement_fail_alloc_counter ())
    536     {
    537       _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
    538 
    539       return NULL;
    540     }
    541 #endif
    542 
    543   if (bytes == 0)
    544     return NULL;
    545 #ifdef DBUS_BUILD_TESTS
    546   else if (fail_size != 0 && bytes > fail_size)
    547     return NULL;
    548   else if (guards)
    549     {
    550       void *block;
    551 
    552       block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
    553 
    554       if (block)
    555         {
    556           _dbus_atomic_inc (&n_blocks_outstanding);
    557         }
    558       else if (malloc_cannot_fail)
    559         {
    560           _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n",
    561               (long) bytes, (long) GUARD_EXTRA_SIZE);
    562           _dbus_abort ();
    563         }
    564 
    565       return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
    566     }
    567 #endif
    568   else
    569     {
    570       void *mem;
    571       mem = calloc (bytes, 1);
    572 
    573 #ifdef DBUS_BUILD_TESTS
    574       if (mem)
    575         {
    576           _dbus_atomic_inc (&n_blocks_outstanding);
    577         }
    578       else if (malloc_cannot_fail)
    579         {
    580           _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes);
    581           _dbus_abort ();
    582         }
    583 #endif
    584 
    585       return mem;
    586     }
    587 }
    588 
    589 /**
    590  * Resizes a block of memory previously allocated by dbus_malloc() or
    591  * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes
    592  * is zero on all platforms. Returns #NULL if the resize fails.
    593  * If the resize fails, the memory is not freed.
    594  *
    595  * @param memory block to be resized
    596  * @param bytes new size of the memory block
    597  * @return allocated memory, or #NULL if the resize fails.
    598  */
    599 void*
    600 dbus_realloc (void  *memory,
    601               size_t bytes)
    602 {
    603 #ifdef DBUS_BUILD_TESTS
    604   _dbus_initialize_malloc_debug ();
    605 
    606   if (_dbus_decrement_fail_alloc_counter ())
    607     {
    608       _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
    609 
    610       return NULL;
    611     }
    612 #endif
    613 
    614   if (bytes == 0) /* guarantee this is safe */
    615     {
    616       dbus_free (memory);
    617       return NULL;
    618     }
    619 #ifdef DBUS_BUILD_TESTS
    620   else if (fail_size != 0 && bytes > fail_size)
    621     return NULL;
    622   else if (guards)
    623     {
    624       if (memory)
    625         {
    626           size_t old_bytes;
    627           void *block;
    628 
    629           check_guards (memory, FALSE);
    630 
    631           block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
    632                            bytes + GUARD_EXTRA_SIZE);
    633 
    634           if (block == NULL)
    635             {
    636               if (malloc_cannot_fail)
    637                 {
    638                   _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n",
    639                       memory, (long) bytes, (long) GUARD_EXTRA_SIZE);
    640                   _dbus_abort ();
    641                 }
    642 
    643               return NULL;
    644             }
    645 
    646           old_bytes = *(dbus_uint32_t*)block;
    647           if (bytes >= old_bytes)
    648             /* old guards shouldn't have moved */
    649             check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
    650 
    651           return set_guards (block, bytes, SOURCE_REALLOC);
    652         }
    653       else
    654         {
    655           void *block;
    656 
    657           block = malloc (bytes + GUARD_EXTRA_SIZE);
    658 
    659           if (block)
    660             {
    661               _dbus_atomic_inc (&n_blocks_outstanding);
    662             }
    663           else if (malloc_cannot_fail)
    664             {
    665               _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
    666                   (long) bytes, (long) GUARD_EXTRA_SIZE);
    667               _dbus_abort ();
    668             }
    669 
    670           return set_guards (block, bytes, SOURCE_REALLOC_NULL);
    671         }
    672     }
    673 #endif
    674   else
    675     {
    676       void *mem;
    677       mem = realloc (memory, bytes);
    678 
    679 #ifdef DBUS_BUILD_TESTS
    680       if (mem == NULL && malloc_cannot_fail)
    681         {
    682           _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
    683           _dbus_abort ();
    684         }
    685 
    686       if (memory == NULL && mem != NULL)
    687 	    _dbus_atomic_inc (&n_blocks_outstanding);
    688 #endif
    689       return mem;
    690     }
    691 }
    692 
    693 /**
    694  * Frees a block of memory previously allocated by dbus_malloc() or
    695  * dbus_malloc0(). If passed #NULL, does nothing.
    696  *
    697  * @param memory block to be freed
    698  */
    699 void
    700 dbus_free (void  *memory)
    701 {
    702 #ifdef DBUS_BUILD_TESTS
    703   if (guards)
    704     {
    705       check_guards (memory, TRUE);
    706       if (memory)
    707         {
    708 #ifdef DBUS_DISABLE_ASSERT
    709           _dbus_atomic_dec (&n_blocks_outstanding);
    710 #else
    711           dbus_int32_t old_value;
    712 
    713           old_value = _dbus_atomic_dec (&n_blocks_outstanding);
    714           _dbus_assert (old_value >= 1);
    715 #endif
    716 
    717           free (((unsigned char*)memory) - GUARD_START_OFFSET);
    718         }
    719 
    720       return;
    721     }
    722 #endif
    723 
    724   if (memory) /* we guarantee it's safe to free (NULL) */
    725     {
    726 #ifdef DBUS_BUILD_TESTS
    727 #ifdef DBUS_DISABLE_ASSERT
    728       _dbus_atomic_dec (&n_blocks_outstanding);
    729 #else
    730       dbus_int32_t old_value;
    731 
    732       old_value = _dbus_atomic_dec (&n_blocks_outstanding);
    733       _dbus_assert (old_value >= 1);
    734 #endif
    735 #endif
    736 
    737       free (memory);
    738     }
    739 }
    740 
    741 /**
    742  * Frees a #NULL-terminated array of strings.
    743  * If passed #NULL, does nothing.
    744  *
    745  * @param str_array the array to be freed
    746  */
    747 void
    748 dbus_free_string_array (char **str_array)
    749 {
    750   if (str_array)
    751     {
    752       int i;
    753 
    754       i = 0;
    755       while (str_array[i])
    756 	{
    757 	  dbus_free (str_array[i]);
    758 	  i++;
    759 	}
    760 
    761       dbus_free (str_array);
    762     }
    763 }
    764 
    765 /** @} */ /* End of public API docs block */
    766 
    767 
    768 /**
    769  * @addtogroup DBusMemoryInternals
    770  *
    771  * @{
    772  */
    773 
    774 /**
    775  * _dbus_current_generation is used to track each
    776  * time that dbus_shutdown() is called, so we can
    777  * reinit things after it's been called. It is simply
    778  * incremented each time we shut down.
    779  */
    780 int _dbus_current_generation = 1;
    781 
    782 /**
    783  * Represents a function to be called on shutdown.
    784  */
    785 typedef struct ShutdownClosure ShutdownClosure;
    786 
    787 /**
    788  * This struct represents a function to be called on shutdown.
    789  */
    790 struct ShutdownClosure
    791 {
    792   ShutdownClosure *next;     /**< Next ShutdownClosure */
    793   DBusShutdownFunction func; /**< Function to call */
    794   void *data;                /**< Data for function */
    795 };
    796 
    797 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
    798 static ShutdownClosure *registered_globals = NULL;
    799 
    800 /**
    801  * Register a cleanup function to be called exactly once
    802  * the next time dbus_shutdown() is called.
    803  *
    804  * @param func the function
    805  * @param data data to pass to the function
    806  * @returns #FALSE on not enough memory
    807  */
    808 dbus_bool_t
    809 _dbus_register_shutdown_func (DBusShutdownFunction  func,
    810                               void                 *data)
    811 {
    812   ShutdownClosure *c;
    813 
    814   c = dbus_new (ShutdownClosure, 1);
    815 
    816   if (c == NULL)
    817     return FALSE;
    818 
    819   c->func = func;
    820   c->data = data;
    821 
    822   _DBUS_LOCK (shutdown_funcs);
    823 
    824   c->next = registered_globals;
    825   registered_globals = c;
    826 
    827   _DBUS_UNLOCK (shutdown_funcs);
    828 
    829   return TRUE;
    830 }
    831 
    832 /** @} */ /* End of private API docs block */
    833 
    834 
    835 /**
    836  * @addtogroup DBusMemory
    837  *
    838  * @{
    839  */
    840 
    841 /**
    842  * Frees all memory allocated internally by libdbus and
    843  * reverses the effects of dbus_threads_init(). libdbus keeps internal
    844  * global variables, for example caches and thread locks, and it
    845  * can be useful to free these internal data structures.
    846  *
    847  * dbus_shutdown() does NOT free memory that was returned
    848  * to the application. It only returns libdbus-internal
    849  * data structures.
    850  *
    851  * You MUST free all memory and release all reference counts
    852  * returned to you by libdbus prior to calling dbus_shutdown().
    853  *
    854  * You can't continue to use any D-Bus objects, such as connections,
    855  * that were allocated prior to dbus_shutdown(). You can, however,
    856  * start over; call dbus_threads_init() again, create new connections,
    857  * and so forth.
    858  *
    859  * WARNING: dbus_shutdown() is NOT thread safe, it must be called
    860  * while NO other threads are using D-Bus. (Remember, you have to free
    861  * all D-Bus objects and memory before you call dbus_shutdown(), so no
    862  * thread can be using libdbus.)
    863  *
    864  * The purpose of dbus_shutdown() is to allow applications to get
    865  * clean output from memory leak checkers. dbus_shutdown() may also be
    866  * useful if you want to dlopen() libdbus instead of linking to it,
    867  * and want to be able to unload the library again.
    868  *
    869  * There is absolutely no requirement to call dbus_shutdown() - in fact,
    870  * most applications won't bother and should not feel guilty.
    871  *
    872  * You have to know that nobody is using libdbus in your application's
    873  * process before you can call dbus_shutdown(). One implication of this
    874  * is that calling dbus_shutdown() from a library is almost certainly
    875  * wrong, since you don't know what the rest of the app is up to.
    876  *
    877  */
    878 void
    879 dbus_shutdown (void)
    880 {
    881   while (registered_globals != NULL)
    882     {
    883       ShutdownClosure *c;
    884 
    885       c = registered_globals;
    886       registered_globals = c->next;
    887 
    888       (* c->func) (c->data);
    889 
    890       dbus_free (c);
    891     }
    892 
    893   _dbus_current_generation += 1;
    894 }
    895 
    896 /** @} */ /** End of public API docs block */
    897 
    898 #ifdef DBUS_BUILD_TESTS
    899 #include "dbus-test.h"
    900 
    901 /**
    902  * @ingroup DBusMemoryInternals
    903  * Unit test for DBusMemory
    904  * @returns #TRUE on success.
    905  */
    906 dbus_bool_t
    907 _dbus_memory_test (void)
    908 {
    909   dbus_bool_t old_guards;
    910   void *p;
    911   size_t size;
    912 
    913   old_guards = guards;
    914   guards = TRUE;
    915   p = dbus_malloc (4);
    916   if (p == NULL)
    917     _dbus_assert_not_reached ("no memory");
    918   for (size = 4; size < 256; size += 4)
    919     {
    920       p = dbus_realloc (p, size);
    921       if (p == NULL)
    922 	_dbus_assert_not_reached ("no memory");
    923     }
    924   for (size = 256; size != 0; size -= 4)
    925     {
    926       p = dbus_realloc (p, size);
    927       if (p == NULL)
    928 	_dbus_assert_not_reached ("no memory");
    929     }
    930   dbus_free (p);
    931   guards = old_guards;
    932   return TRUE;
    933 }
    934 
    935 #endif
    936