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 #define GUARD_VALUE 0xdeadbeef
81 #define GUARD_INFO_SIZE 8
82 #define GUARD_START_PAD 16
83 #define GUARD_END_PAD 16
84 #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
85 #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
88 #ifdef DBUS_BUILD_TESTS
90 initialize_malloc_debug (void)
94 if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
96 fail_counts = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
97 _dbus_set_fail_alloc_counter (fail_counts);
100 if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
101 fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
103 if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
120 source_string (BlockSource source)
130 case SOURCE_MALLOC_ZERO:
132 case SOURCE_REALLOC_NULL:
133 return "realloc(NULL)";
135 _dbus_assert_not_reached ("Invalid malloc block source ID");
140 check_guards (void *free_block)
142 if (free_block != NULL)
144 unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
145 size_t requested_bytes = *(dbus_uint32_t*)block;
146 BlockSource source = *(dbus_uint32_t*)(block + 4);
153 _dbus_verbose ("Checking %d bytes request from source %s\n",
154 requested_bytes, source_string (source));
158 while (i < GUARD_START_OFFSET)
160 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
161 if (value != GUARD_VALUE)
163 _dbus_warn ("Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
164 requested_bytes, source_string (source),
165 value, i, GUARD_VALUE);
172 i = GUARD_START_OFFSET + requested_bytes;
173 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
175 dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
176 if (value != GUARD_VALUE)
178 _dbus_warn ("Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
179 requested_bytes, source_string (source),
180 value, i, GUARD_VALUE);
188 _dbus_assert_not_reached ("guard value corruption");
193 set_guards (void *real_block,
194 size_t requested_bytes,
197 unsigned char *block = real_block;
203 _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
205 *((dbus_uint32_t*)block) = requested_bytes;
206 *((dbus_uint32_t*)(block + 4)) = source;
209 while (i < GUARD_START_OFFSET)
211 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
216 i = GUARD_START_OFFSET + requested_bytes;
217 while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
219 (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
224 check_guards (block + GUARD_START_OFFSET);
226 return block + GUARD_START_OFFSET;
232 * Allocates the given number of bytes, as with standard
233 * malloc(). Guaranteed to return #NULL if bytes is zero
234 * on all platforms. Returns #NULL if the allocation fails.
235 * The memory must be released with dbus_free().
237 * @param bytes number of bytes to allocate
238 * @return allocated memory, or #NULL if the allocation fails.
241 dbus_malloc (size_t bytes)
243 #ifdef DBUS_BUILD_TESTS
244 initialize_malloc_debug ();
246 if (_dbus_decrement_fail_alloc_counter ())
248 if (fail_counts != -1)
249 _dbus_set_fail_alloc_counter (fail_counts);
255 if (bytes == 0) /* some system mallocs handle this, some don't */
258 else if (fail_size != 0 && bytes > fail_size)
264 block = malloc (bytes + GUARD_EXTRA_SIZE);
265 return set_guards (block, bytes, SOURCE_MALLOC);
269 return malloc (bytes);
273 * Allocates the given number of bytes, as with standard malloc(), but
274 * all bytes are initialized to zero as with calloc(). Guaranteed to
275 * return #NULL if bytes is zero on all platforms. Returns #NULL if the
276 * allocation fails. The memory must be released with dbus_free().
278 * @param bytes number of bytes to allocate
279 * @return allocated memory, or #NULL if the allocation fails.
282 dbus_malloc0 (size_t bytes)
284 #ifdef DBUS_BUILD_TESTS
285 initialize_malloc_debug ();
287 if (_dbus_decrement_fail_alloc_counter ())
289 if (fail_counts != -1)
290 _dbus_set_fail_alloc_counter (fail_counts);
299 else if (fail_size != 0 && bytes > fail_size)
305 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
306 return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
310 return calloc (bytes, 1);
314 * Resizes a block of memory previously allocated by dbus_malloc() or
315 * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes
316 * is zero on all platforms. Returns #NULL if the resize fails.
317 * If the resize fails, the memory is not freed.
319 * @param memory block to be resized
320 * @param bytes new size of the memory block
321 * @return allocated memory, or #NULL if the resize fails.
324 dbus_realloc (void *memory,
327 #ifdef DBUS_BUILD_TESTS
328 initialize_malloc_debug ();
330 if (_dbus_decrement_fail_alloc_counter ())
332 if (fail_counts != -1)
333 _dbus_set_fail_alloc_counter (fail_counts);
339 if (bytes == 0) /* guarantee this is safe */
345 else if (fail_size != 0 && bytes > fail_size)
353 check_guards (memory);
355 block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
356 bytes + GUARD_EXTRA_SIZE);
358 /* old guards shouldn't have moved */
359 check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
361 return set_guards (block, bytes, SOURCE_REALLOC);
367 block = malloc (bytes + GUARD_EXTRA_SIZE);
368 return set_guards (block, bytes, SOURCE_REALLOC_NULL);
374 return realloc (memory, bytes);
379 * Frees a block of memory previously allocated by dbus_malloc() or
380 * dbus_malloc0(). If passed #NULL, does nothing.
382 * @param memory block to be freed
385 dbus_free (void *memory)
387 #ifdef DBUS_BUILD_TESTS
390 check_guards (memory);
392 free (((unsigned char*)memory) - GUARD_START_OFFSET);
397 if (memory) /* we guarantee it's safe to free (NULL) */
402 * Frees a #NULL-terminated array of strings.
403 * If passed #NULL, does nothing.
405 * @param str_array the array to be freed
408 dbus_free_string_array (char **str_array)
417 dbus_free (str_array[i]);
421 dbus_free (str_array);