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