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
_dbus_initialize_malloc_debug(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
_dbus_disable_mem_pools(void)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
_dbus_set_fail_alloc_counter(int until_next_fail)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
_dbus_get_fail_alloc_counter(void)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
_dbus_set_fail_alloc_failures(int failures_per_failure)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
_dbus_get_fail_alloc_failures(void)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
_dbus_decrement_fail_alloc_counter(void)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
_dbus_get_malloc_blocks_outstanding(void)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*
source_string(BlockSource source)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
check_guards(void * free_block,dbus_bool_t overwrite)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*
set_guards(void * real_block,size_t requested_bytes,BlockSource source)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*
dbus_malloc(size_t bytes)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*
dbus_malloc0(size_t bytes)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*
dbus_realloc(void * memory,size_t bytes)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
dbus_free(void * memory)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
dbus_free_string_array(char ** str_array)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
_dbus_register_shutdown_func(DBusShutdownFunction func,void * data)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
dbus_shutdown(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
_dbus_memory_test(void)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