1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-memory.c D-BUS memory handling
4 * Copyright (C) 2002, 2003 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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
24 #include "dbus-memory.h"
25 #include "dbus-internals.h"
30 * @defgroup DBusMemory Memory Allocation
32 * @brief dbus_malloc(), dbus_free(), etc.
34 * Functions and macros related to allocating and releasing
43 * Safe macro for using dbus_malloc(). Accepts the type
44 * to allocate and the number of type instances to
45 * allocate as arguments, and returns a memory block
46 * cast to the desired type, instead of as a void*.
48 * @param type type name to allocate
49 * @param count number of instances in the allocated array
50 * @returns the new memory block or #NULL on failure
56 * Safe macro for using dbus_malloc0(). Accepts the type
57 * to allocate and the number of type instances to
58 * allocate as arguments, and returns a memory block
59 * cast to the desired type, instead of as a void*.
60 * The allocated array is initialized to all-bits-zero.
62 * @param type type name to allocate
63 * @param count number of instances in the allocated array
64 * @returns the new memory block or #NULL on failure
68 * @typedef DBusFreeFunction
70 * The type of a function which frees a block of memory.
72 * @param memory the memory to free
75 #ifdef DBUS_BUILD_TESTS
76 static dbus_bool_t inited = FALSE;
77 static int fail_counts = -1;
78 static size_t fail_size = 0;
79 static dbus_bool_t guards = FALSE;
80 /** value stored in guard padding for debugging buffer overrun */
81 #define GUARD_VALUE 0xdeadbeef
82 /** size of the information about the block stored in guard mode */
83 #define GUARD_INFO_SIZE 8
84 /** size of the GUARD_VALUE-filled padding after the header info */
85 #define GUARD_START_PAD 16
86 /** size of the GUARD_VALUE-filled padding at the end of the block */
87 #define GUARD_END_PAD 16
88 /** size of stuff at start of block */
89 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
90 /** total extra size over the requested allocation for guard stuff */
91 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
94 #ifdef DBUS_BUILD_TESTS
96 initialize_malloc_debug (void)
100 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
102 fail_counts = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
103 _dbus_set_fail_alloc_counter (fail_counts);
106 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
107 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
109 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
117 * Where the block came from.
129 source_string (BlockSource source)
139 case SOURCE_MALLOC_ZERO:
141 case SOURCE_REALLOC_NULL:
142 return "realloc(NULL)";
144 _dbus_assert_not_reached ("Invalid malloc block source ID");
149 check_guards (void *free_block)
151 if (free_block != NULL)
153 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
154 size_t requested_bytes = *(dbus_uint32_t*)block;
155 BlockSource source = *(dbus_uint32_t*)(block + 4);
162 _dbus_verbose ("Checking %d bytes request from source %s\n",
163 requested_bytes, source_string (source));
167 while (i < GUARD_START_OFFSET)
169 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
170 if (value != GUARD_VALUE)
172 _dbus_warn ("Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
173 requested_bytes, source_string (source),
174 value, i, GUARD_VALUE);
181 i = GUARD_START_OFFSET + requested_bytes;
182 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
184 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
185 if (value != GUARD_VALUE)
187 _dbus_warn ("Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
188 requested_bytes, source_string (source),
189 value, i, GUARD_VALUE);
197 _dbus_assert_not_reached ("guard value corruption");
202 set_guards (void *real_block,
203 size_t requested_bytes,
206 unsigned char *block = real_block;
212 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
214 *((dbus_uint32_t*)block) = requested_bytes;
215 *((dbus_uint32_t*)(block + 4)) = source;
218 while (i < GUARD_START_OFFSET)
220 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
225 i = GUARD_START_OFFSET + requested_bytes;
226 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
228 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
233 check_guards (block + GUARD_START_OFFSET);
235 return block + GUARD_START_OFFSET;
241 * Allocates the given number of bytes, as with standard
242 * malloc(). Guaranteed to return #NULL if bytes is zero
243 * on all platforms. Returns #NULL if the allocation fails.
244 * The memory must be released with dbus_free().
246 * @param bytes number of bytes to allocate
247 * @return allocated memory, or #NULL if the allocation fails.
250 dbus_malloc (size_t bytes)
252 #ifdef DBUS_BUILD_TESTS
253 initialize_malloc_debug ();
255 if (_dbus_decrement_fail_alloc_counter ())
257 if (fail_counts != -1)
258 _dbus_set_fail_alloc_counter (fail_counts);
260 _dbus_verbose (" FAILING malloc of %d bytes\n", bytes);
266 if (bytes == 0) /* some system mallocs handle this, some don't */
269 else if (fail_size != 0 && bytes > fail_size)
275 block = malloc (bytes + GUARD_EXTRA_SIZE);
276 return set_guards (block, bytes, SOURCE_MALLOC);
280 return malloc (bytes);
284 * Allocates the given number of bytes, as with standard malloc(), but
285 * all bytes are initialized to zero as with calloc(). Guaranteed to
286 * return #NULL if bytes is zero on all platforms. Returns #NULL if the
287 * allocation fails. The memory must be released with dbus_free().
289 * @param bytes number of bytes to allocate
290 * @return allocated memory, or #NULL if the allocation fails.
293 dbus_malloc0 (size_t bytes)
295 #ifdef DBUS_BUILD_TESTS
296 initialize_malloc_debug ();
298 if (_dbus_decrement_fail_alloc_counter ())
300 if (fail_counts != -1)
301 _dbus_set_fail_alloc_counter (fail_counts);
303 _dbus_verbose (" FAILING malloc0 of %d bytes\n", bytes);
312 else if (fail_size != 0 && bytes > fail_size)
318 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
319 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
323 return calloc (bytes, 1);
327 * Resizes a block of memory previously allocated by dbus_malloc() or
328 * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes
329 * is zero on all platforms. Returns #NULL if the resize fails.
330 * If the resize fails, the memory is not freed.
332 * @param memory block to be resized
333 * @param bytes new size of the memory block
334 * @return allocated memory, or #NULL if the resize fails.
337 dbus_realloc (void *memory,
340 #ifdef DBUS_BUILD_TESTS
341 initialize_malloc_debug ();
343 if (_dbus_decrement_fail_alloc_counter ())
345 if (fail_counts != -1)
346 _dbus_set_fail_alloc_counter (fail_counts);
348 _dbus_verbose (" FAILING realloc of %d bytes\n", bytes);
354 if (bytes == 0) /* guarantee this is safe */
360 else if (fail_size != 0 && bytes > fail_size)
368 check_guards (memory);
370 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
371 bytes + GUARD_EXTRA_SIZE);
373 /* old guards shouldn't have moved */
374 check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
376 return set_guards (block, bytes, SOURCE_REALLOC);
382 block = malloc (bytes + GUARD_EXTRA_SIZE);
383 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
389 return realloc (memory, bytes);
394 * Frees a block of memory previously allocated by dbus_malloc() or
395 * dbus_malloc0(). If passed #NULL, does nothing.
397 * @param memory block to be freed
400 dbus_free (void *memory)
402 #ifdef DBUS_BUILD_TESTS
405 check_guards (memory);
407 free (((unsigned char*)memory) - GUARD_START_OFFSET);
412 if (memory) /* we guarantee it's safe to free (NULL) */
417 * Frees a #NULL-terminated array of strings.
418 * If passed #NULL, does nothing.
420 * @param str_array the array to be freed
423 dbus_free_string_array (char **str_array)
432 dbus_free (str_array[i]);
436 dbus_free (str_array);