2003-04-27 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-memory.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
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 1.2
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 /**
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 /**
43  * @def dbus_new
44  *
45  * Safe macro for using dbus_malloc(). Accepts the type
46  * to allocate and the number of type instances to
47  * allocate as arguments, and returns a memory block
48  * cast to the desired type, instead of as a void*.
49  *
50  * @param type type name to allocate
51  * @param count number of instances in the allocated array
52  * @returns the new memory block or #NULL on failure
53  */
54
55 /**
56  * @def dbus_new0
57  *
58  * Safe macro for using dbus_malloc0(). 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  * The allocated array is initialized to all-bits-zero.
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  * @typedef DBusFreeFunction
71  *
72  * The type of a function which frees a block of memory.
73  *
74  * @param memory the memory to free
75  */
76
77 #ifdef DBUS_BUILD_TESTS
78 static dbus_bool_t debug_initialized = FALSE;
79 static int fail_nth = -1;
80 static size_t fail_size = 0;
81 static int fail_alloc_counter = _DBUS_INT_MAX;
82 static int n_failures_per_failure = 1;
83 static int n_failures_this_failure = 0;
84 static dbus_bool_t guards = FALSE;
85 static dbus_bool_t disable_mem_pools = FALSE;
86 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
87 static int n_blocks_outstanding = 0;
88
89 /** value stored in guard padding for debugging buffer overrun */
90 #define GUARD_VALUE 0xdeadbeef
91 /** size of the information about the block stored in guard mode */
92 #define GUARD_INFO_SIZE 8
93 /** size of the GUARD_VALUE-filled padding after the header info  */
94 #define GUARD_START_PAD 16
95 /** size of the GUARD_VALUE-filled padding at the end of the block */
96 #define GUARD_END_PAD 16
97 /** size of stuff at start of block */
98 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
99 /** total extra size over the requested allocation for guard stuff */
100 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
101
102 static void
103 _dbus_initialize_malloc_debug (void)
104 {
105   if (!debug_initialized)
106     {
107       debug_initialized = TRUE;
108       
109       if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
110         {
111           fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
112           fail_alloc_counter = fail_nth;
113           _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
114         }
115       
116       if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
117         {
118           fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
119           _dbus_verbose ("Will fail mallocs over %d bytes\n",
120                          fail_size);
121         }
122
123       if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
124         {
125           guards = TRUE;
126           _dbus_verbose ("Will use malloc guards\n");
127         }
128
129       if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
130         {
131           disable_mem_pools = TRUE;
132           _dbus_verbose ("Will disable memory pools\n");
133         }
134
135       if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
136         {
137           backtrace_on_fail_alloc = TRUE;
138           _dbus_verbose ("Will backtrace on failing a malloc\n");
139         }
140     }
141 }
142
143 /**
144  * Whether to turn off mem pools, useful for leak checking.
145  *
146  * @returns #TRUE if mempools should not be used.
147  */
148 dbus_bool_t
149 _dbus_disable_mem_pools (void)
150 {
151   _dbus_initialize_malloc_debug ();
152   return disable_mem_pools;
153 }
154
155 /**
156  * Sets the number of allocations until we simulate a failed
157  * allocation. If set to 0, the next allocation to run
158  * fails; if set to 1, one succeeds then the next fails; etc.
159  * Set to _DBUS_INT_MAX to not fail anything. 
160  *
161  * @param until_next_fail number of successful allocs before one fails
162  */
163 void
164 _dbus_set_fail_alloc_counter (int until_next_fail)
165 {
166   _dbus_initialize_malloc_debug ();
167
168   fail_alloc_counter = until_next_fail;
169
170 #if 0
171   _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
172 #endif
173 }
174
175 /**
176  * Gets the number of successful allocs until we'll simulate
177  * a failed alloc.
178  *
179  * @returns current counter value
180  */
181 int
182 _dbus_get_fail_alloc_counter (void)
183 {
184   _dbus_initialize_malloc_debug ();
185
186   return fail_alloc_counter;
187 }
188
189 /**
190  * Sets how many mallocs to fail when the fail alloc counter reaches
191  * 0.
192  *
193  * @param failures_per_failure number to fail
194  */
195 void
196 _dbus_set_fail_alloc_failures (int failures_per_failure)
197 {
198   n_failures_per_failure = failures_per_failure;
199 }
200
201 /**
202  * Gets the number of failures we'll have when the fail malloc
203  * counter reaches 0.
204  *
205  * @returns number of failures planned
206  */
207 int
208 _dbus_get_fail_alloc_failures (void)
209 {
210   return n_failures_per_failure;
211 }
212
213 /**
214  * Called when about to alloc some memory; if
215  * it returns #TRUE, then the allocation should
216  * fail. If it returns #FALSE, then the allocation
217  * should not fail.
218  *
219  * @returns #TRUE if this alloc should fail
220  */
221 dbus_bool_t
222 _dbus_decrement_fail_alloc_counter (void)
223 {
224   _dbus_initialize_malloc_debug ();
225   
226   if (fail_alloc_counter <= 0)
227     {
228       if (backtrace_on_fail_alloc)
229         _dbus_print_backtrace ();
230
231       _dbus_verbose ("failure %d\n", n_failures_this_failure);
232       
233       n_failures_this_failure += 1;
234       if (n_failures_this_failure >= n_failures_per_failure)
235         {
236           if (fail_nth >= 0)
237             fail_alloc_counter = fail_nth;
238           else
239             fail_alloc_counter = _DBUS_INT_MAX;
240
241           n_failures_this_failure = 0;
242
243           _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
244         }
245       
246       return TRUE;
247     }
248   else
249     {
250       fail_alloc_counter -= 1;
251       return FALSE;
252     }
253 }
254
255 /**
256  * Get the number of outstanding malloc()'d blocks.
257  *
258  * @returns number of blocks
259  */
260 int
261 _dbus_get_malloc_blocks_outstanding (void)
262 {
263   return n_blocks_outstanding;
264 }
265
266 /**
267  * Where the block came from.
268  */
269 typedef enum
270 {
271   SOURCE_UNKNOWN,
272   SOURCE_MALLOC,
273   SOURCE_REALLOC,
274   SOURCE_MALLOC_ZERO,
275   SOURCE_REALLOC_NULL
276 } BlockSource;
277
278 static const char*
279 source_string (BlockSource source)
280 {
281   switch (source)
282     {
283     case SOURCE_UNKNOWN:
284       return "unknown";
285     case SOURCE_MALLOC:
286       return "malloc";
287     case SOURCE_REALLOC:
288       return "realloc";
289     case SOURCE_MALLOC_ZERO:
290       return "malloc0";
291     case SOURCE_REALLOC_NULL:
292       return "realloc(NULL)";
293     }
294   _dbus_assert_not_reached ("Invalid malloc block source ID");
295   return "invalid!";
296 }
297
298 static void
299 check_guards (void *free_block)
300 {
301   if (free_block != NULL)
302     {
303       unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
304       size_t requested_bytes = *(dbus_uint32_t*)block;
305       BlockSource source = *(dbus_uint32_t*)(block + 4);
306       unsigned int i;
307       dbus_bool_t failed;
308
309       failed = FALSE;
310
311 #if 0
312       _dbus_verbose ("Checking %d bytes request from source %s\n",
313                      requested_bytes, source_string (source));
314 #endif
315       
316       i = GUARD_INFO_SIZE;
317       while (i < GUARD_START_OFFSET)
318         {
319           dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
320           if (value != GUARD_VALUE)
321             {
322               _dbus_warn ("Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
323                           requested_bytes, source_string (source),
324                           value, i, GUARD_VALUE);
325               failed = TRUE;
326             }
327           
328           i += 4;
329         }
330
331       i = GUARD_START_OFFSET + requested_bytes;
332       while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
333         {
334           dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
335           if (value != GUARD_VALUE)
336             {
337               _dbus_warn ("Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
338                           requested_bytes, source_string (source),
339                           value, i, GUARD_VALUE);
340               failed = TRUE;
341             }
342           
343           i += 4;
344         }
345
346       if (failed)
347         _dbus_assert_not_reached ("guard value corruption");
348     }
349 }
350
351 static void*
352 set_guards (void       *real_block,
353             size_t      requested_bytes,
354             BlockSource source)
355 {
356   unsigned char *block = real_block;
357   unsigned int i;
358   
359   if (block == NULL)
360     return NULL;
361
362   _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
363   
364   *((dbus_uint32_t*)block) = requested_bytes;
365   *((dbus_uint32_t*)(block + 4)) = source;
366
367   i = GUARD_INFO_SIZE;
368   while (i < GUARD_START_OFFSET)
369     {
370       (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
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*) &block[i]) = GUARD_VALUE;
379       
380       i += 4;
381     }
382   
383   check_guards (block + GUARD_START_OFFSET);
384   
385   return block + GUARD_START_OFFSET;
386 }
387
388 #endif
389
390 /**
391  * Allocates the given number of bytes, as with standard
392  * malloc(). Guaranteed to return #NULL if bytes is zero
393  * on all platforms. Returns #NULL if the allocation fails.
394  * The memory must be released with dbus_free().
395  *
396  * @param bytes number of bytes to allocate
397  * @return allocated memory, or #NULL if the allocation fails.
398  */
399 void*
400 dbus_malloc (size_t bytes)
401 {
402 #ifdef DBUS_BUILD_TESTS
403   _dbus_initialize_malloc_debug ();
404   
405   if (_dbus_decrement_fail_alloc_counter ())
406     {
407       _dbus_verbose (" FAILING malloc of %d bytes\n", bytes);
408       
409       return NULL;
410     }
411 #endif
412   
413   if (bytes == 0) /* some system mallocs handle this, some don't */
414     return NULL;
415 #if DBUS_BUILD_TESTS
416   else if (fail_size != 0 && bytes > fail_size)
417     return NULL;
418   else if (guards)
419     {
420       void *block;
421
422       block = malloc (bytes + GUARD_EXTRA_SIZE);
423       if (block)
424         n_blocks_outstanding += 1;
425       
426       return set_guards (block, bytes, SOURCE_MALLOC);
427     }
428 #endif
429   else
430     {
431       void *mem;
432       mem = malloc (bytes);
433 #ifdef DBUS_BUILD_TESTS
434       if (mem)
435         n_blocks_outstanding += 1;
436 #endif
437       return mem;
438     }
439 }
440
441 /**
442  * Allocates the given number of bytes, as with standard malloc(), but
443  * all bytes are initialized to zero as with calloc(). Guaranteed to
444  * return #NULL if bytes is zero on all platforms. Returns #NULL if the
445  * allocation fails.  The memory must be released with dbus_free().
446  *
447  * @param bytes number of bytes to allocate
448  * @return allocated memory, or #NULL if the allocation fails.
449  */
450 void*
451 dbus_malloc0 (size_t bytes)
452 {
453 #ifdef DBUS_BUILD_TESTS
454   _dbus_initialize_malloc_debug ();
455   
456   if (_dbus_decrement_fail_alloc_counter ())
457     {
458       _dbus_verbose (" FAILING malloc0 of %d bytes\n", bytes);
459       
460       return NULL;
461     }
462 #endif
463
464   if (bytes == 0)
465     return NULL;
466 #if DBUS_BUILD_TESTS
467   else if (fail_size != 0 && bytes > fail_size)
468     return NULL;
469   else if (guards)
470     {
471       void *block;
472
473       block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
474       if (block)
475         n_blocks_outstanding += 1;
476       return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
477     }
478 #endif
479   else
480     {
481       void *mem;
482       mem = calloc (bytes, 1);
483 #ifdef DBUS_BUILD_TESTS
484       if (mem)
485         n_blocks_outstanding += 1;
486 #endif
487       return mem;
488     }
489 }
490
491 /**
492  * Resizes a block of memory previously allocated by dbus_malloc() or
493  * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes
494  * is zero on all platforms. Returns #NULL if the resize fails.
495  * If the resize fails, the memory is not freed.
496  *
497  * @param memory block to be resized
498  * @param bytes new size of the memory block
499  * @return allocated memory, or #NULL if the resize fails.
500  */
501 void*
502 dbus_realloc (void  *memory,
503               size_t bytes)
504 {
505 #ifdef DBUS_BUILD_TESTS
506   _dbus_initialize_malloc_debug ();
507   
508   if (_dbus_decrement_fail_alloc_counter ())
509     {
510       _dbus_verbose (" FAILING realloc of %d bytes\n", bytes);
511       
512       return NULL;
513     }
514 #endif
515   
516   if (bytes == 0) /* guarantee this is safe */
517     {
518       dbus_free (memory);
519       return NULL;
520     }
521 #if DBUS_BUILD_TESTS
522   else if (fail_size != 0 && bytes > fail_size)
523     return NULL;
524   else if (guards)
525     {
526       if (memory)
527         {
528           void *block;
529           
530           check_guards (memory);
531           
532           block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
533                            bytes + GUARD_EXTRA_SIZE);
534
535           if (block)
536             /* old guards shouldn't have moved */
537             check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
538           
539           return set_guards (block, bytes, SOURCE_REALLOC);
540         }
541       else
542         {
543           void *block;
544           
545           block = malloc (bytes + GUARD_EXTRA_SIZE);
546
547           if (block)
548             n_blocks_outstanding += 1;
549           
550           return set_guards (block, bytes, SOURCE_REALLOC_NULL);   
551         }
552     }
553 #endif
554   else
555     {
556       void *mem;
557       mem = realloc (memory, bytes);
558 #ifdef DBUS_BUILD_TESTS
559       if (memory == NULL && mem != NULL)
560         n_blocks_outstanding += 1;
561 #endif
562       return mem;
563     }
564 }
565
566 /**
567  * Frees a block of memory previously allocated by dbus_malloc() or
568  * dbus_malloc0(). If passed #NULL, does nothing.
569  * 
570  * @param memory block to be freed
571  */
572 void
573 dbus_free (void  *memory)
574 {
575 #ifdef DBUS_BUILD_TESTS
576   if (guards)
577     {
578       check_guards (memory);
579       if (memory)
580         {
581           n_blocks_outstanding -= 1;
582           
583           _dbus_assert (n_blocks_outstanding >= 0);
584           
585           free (((unsigned char*)memory) - GUARD_START_OFFSET);
586         }
587       
588       return;
589     }
590 #endif
591     
592   if (memory) /* we guarantee it's safe to free (NULL) */
593     {
594 #ifdef DBUS_BUILD_TESTS
595       n_blocks_outstanding -= 1;
596       
597       _dbus_assert (n_blocks_outstanding >= 0);
598 #endif
599
600       free (memory);
601     }
602 }
603
604 /**
605  * Frees a #NULL-terminated array of strings.
606  * If passed #NULL, does nothing.
607  *
608  * @param str_array the array to be freed
609  */
610 void
611 dbus_free_string_array (char **str_array)
612 {
613   if (str_array)
614     {
615       int i;
616
617       i = 0;
618       while (str_array[i])
619         {
620           dbus_free (str_array[i]);
621           i++;
622         }
623
624       dbus_free (str_array);
625     }
626 }
627
628 /**
629  * _dbus_current_generation is used to track each
630  * time that dbus_shutdown() is called, so we can
631  * reinit things after it's been called. It is simply
632  * incremented each time we shut down.
633  */
634 int _dbus_current_generation = 1;
635
636 /**
637  * Represents a function to be called on shutdown.
638  */
639 typedef struct ShutdownClosure ShutdownClosure;
640
641 /**
642  * This struct represents a function to be called on shutdown.
643  */
644 struct ShutdownClosure
645 {
646   ShutdownClosure *next;     /**< Next ShutdownClosure */
647   DBusShutdownFunction func; /**< Function to call */
648   void *data;                /**< Data for function */
649 };
650
651 _DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
652 static ShutdownClosure *registered_globals = NULL;
653
654 /**
655  * The D-BUS library keeps some internal global variables, for example
656  * to cache the username of the current process.  This function is
657  * used to free these global variables.  It is really useful only for
658  * leak-checking cleanliness and the like. WARNING: this function is
659  * NOT thread safe, it must be called while NO other threads are using
660  * D-BUS. You cannot continue using D-BUS after calling this function,
661  * as it does things like free global mutexes created by
662  * dbus_threads_init(). To use a D-BUS function after calling
663  * dbus_shutdown(), you have to start over from scratch, e.g. calling
664  * dbus_threads_init() again.
665  */
666 void
667 dbus_shutdown (void)
668 {
669   while (registered_globals != NULL)
670     {
671       ShutdownClosure *c;
672
673       c = registered_globals;
674       registered_globals = c->next;
675       
676       (* c->func) (c->data);
677       
678       dbus_free (c);
679     }
680
681   _dbus_current_generation += 1;
682 }
683
684 /**
685  * Register a cleanup function to be called exactly once
686  * the next time dbus_shutdown() is called.
687  *
688  * @param func the function
689  * @param data data to pass to the function
690  * @returns #FALSE on not enough memory
691  */
692 dbus_bool_t
693 _dbus_register_shutdown_func (DBusShutdownFunction  func,
694                               void                 *data)
695 {
696   ShutdownClosure *c;
697
698   c = dbus_new (ShutdownClosure, 1);
699
700   if (c == NULL)
701     return FALSE;
702
703   c->func = func;
704   c->data = data;
705
706   _DBUS_LOCK (shutdown_funcs);
707   
708   c->next = registered_globals;
709   registered_globals = c;
710
711   _DBUS_UNLOCK (shutdown_funcs);
712   
713   return TRUE;
714 }
715
716 /** @} */