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