/** * Allocates the given number of bytes, as with standard malloc(), but * all bytes are initialized to zero as with calloc(). Guaranteed to * return #NULL if bytes is zero on all platforms. Returns #NULL if the * allocation fails. The memory must be released with dbus_free(). * * dbus_malloc0() memory is NOT safe to free with regular free() from * the C library. Free it with dbus_free() only. * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc0 (size_t bytes) { #ifdef DBUS_BUILD_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) return NULL; #ifdef DBUS_BUILD_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { void *block; block = calloc (bytes + GUARD_EXTRA_SIZE, 1); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_MALLOC_ZERO); } #endif else { void *mem; mem = calloc (bytes, 1); #ifdef DBUS_BUILD_TESTS if (mem) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes); _dbus_abort (); } #endif return mem; } }
/** * Allocates the given number of bytes, as with standard * malloc(). Guaranteed to return #NULL if bytes is zero * on all platforms. Returns #NULL if the allocation fails. * The memory must be released with dbus_free(). * * dbus_malloc() memory is NOT safe to free with regular free() from * the C library. Free it with dbus_free() only. * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc (size_t bytes) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* some system mallocs handle this, some don't */ return NULL; #ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld + %ld)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_MALLOC); } #endif else { void *mem; mem = malloc (bytes); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); _dbus_abort (); } #endif return mem; } }
/** * Allocates the given number of bytes, as with standard * malloc(). Guaranteed to return #NULL if bytes is zero * on all platforms. Returns #NULL if the allocation fails. * The memory must be released with dbus_free(). * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc (size_t bytes) { #ifdef DBUS_BUILD_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* some system mallocs handle this, some don't */ return NULL; #ifdef DBUS_BUILD_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) n_blocks_outstanding += 1; return set_guards (block, bytes, SOURCE_MALLOC); } #endif else { void *mem; mem = malloc (bytes); #ifdef DBUS_BUILD_TESTS if (mem) n_blocks_outstanding += 1; #endif return mem; } }
/** * Resizes a block of memory previously allocated by dbus_malloc() or * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes * is zero on all platforms. Returns #NULL if the resize fails. * If the resize fails, the memory is not freed. * * @param memory block to be resized * @param bytes new size of the memory block * @return allocated memory, or #NULL if the resize fails. */ void* dbus_realloc (void *memory, size_t bytes) { #ifdef DBUS_BUILD_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* guarantee this is safe */ { dbus_free (memory); return NULL; } #ifdef DBUS_BUILD_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { if (memory) { size_t old_bytes; void *block; check_guards (memory, FALSE); block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); old_bytes = *(dbus_uint32_t*)block; if (block && bytes >= old_bytes) /* old guards shouldn't have moved */ check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); return set_guards (block, bytes, SOURCE_REALLOC); } else { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) _dbus_atomic_inc (&n_blocks_outstanding); return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } #endif else { void *mem; mem = realloc (memory, bytes); #ifdef DBUS_BUILD_TESTS if (memory == NULL && mem != NULL) _dbus_atomic_inc (&n_blocks_outstanding); #endif return mem; } }
/** * Resizes a block of memory previously allocated by dbus_malloc() or * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes * is zero on all platforms. Returns #NULL if the resize fails. * If the resize fails, the memory is not freed. * * @param memory block to be resized * @param bytes new size of the memory block * @return allocated memory, or #NULL if the resize fails. */ void* _dbus_realloc (void *memory, size_t bytes, const char *file, int line) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* guarantee this is safe */ { dbus_free (memory); return NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { if (memory) { size_t old_bytes; void *block; check_guards (memory, FALSE); block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); if (block == NULL) { if (malloc_cannot_fail) { _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n", memory, (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return NULL; } dbus_track_free (((unsigned char*)memory) - GUARD_START_OFFSET); dbus_track_realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE, file, line); old_bytes = *(dbus_uint32_t*)block; if (bytes >= old_bytes) /* old guards shouldn't have moved */ check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); return set_guards (block, bytes, SOURCE_REALLOC); } else { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); dbus_track_malloc(block, bytes + GUARD_EXTRA_SIZE, file, line); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld + %ld)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } #endif else { void *mem; mem = realloc (memory, bytes); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem == NULL && malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); _dbus_abort (); } if (memory == NULL && mem != NULL) _dbus_atomic_inc (&n_blocks_outstanding); #endif dbus_track_free (memory); dbus_track_realloc (mem, bytes, file, line); return mem; } }
/** * Allocates an object from the memory pool. * The object must be freed with _dbus_mem_pool_dealloc(). * * @param pool the memory pool * @returns the allocated object or #NULL if no memory. */ void* _dbus_mem_pool_alloc (DBusMemPool *pool) { #ifdef DBUS_BUILD_TESTS if (_dbus_disable_mem_pools ()) { DBusMemBlock *block; int alloc_size; /* This is obviously really silly, but it's * debug-mode-only code that is compiled out * when tests are disabled (_dbus_disable_mem_pools() * is a constant expression FALSE so this block * should vanish) */ alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->element_size; if (pool->zero_elements) block = dbus_malloc0 (alloc_size); else block = dbus_malloc (alloc_size); if (block != NULL) { block->next = pool->blocks; pool->blocks = block; pool->allocated_elements += 1; return (void*) &block->elements[0]; } else return NULL; } else #endif { if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING mempool alloc\n"); return NULL; } else if (pool->free_elements) { DBusFreedElement *element = pool->free_elements; pool->free_elements = pool->free_elements->next; if (pool->zero_elements) memset (element, '\0', pool->element_size); pool->allocated_elements += 1; return element; } else { void *element; if (pool->blocks == NULL || pool->blocks->used_so_far == pool->block_size) { /* Need a new block */ DBusMemBlock *block; int alloc_size; #ifdef DBUS_BUILD_TESTS int saved_counter; #endif if (pool->block_size <= _DBUS_INT_MAX / 4) /* avoid overflow */ { /* use a larger block size for our next block */ pool->block_size *= 2; _dbus_assert ((pool->block_size % pool->element_size) == 0); } alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->block_size; #ifdef DBUS_BUILD_TESTS /* We save/restore the counter, so that memory pools won't * cause a given function to have different number of * allocations on different invocations. i.e. when testing * we want consistent alloc patterns. So we skip our * malloc here for purposes of failed alloc simulation. */ saved_counter = _dbus_get_fail_alloc_counter (); _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); #endif if (pool->zero_elements) block = dbus_malloc0 (alloc_size); else block = dbus_malloc (alloc_size); #ifdef DBUS_BUILD_TESTS _dbus_set_fail_alloc_counter (saved_counter); _dbus_assert (saved_counter == _dbus_get_fail_alloc_counter ()); #endif if (block == NULL) return NULL; block->used_so_far = 0; block->next = pool->blocks; pool->blocks = block; } element = &pool->blocks->elements[pool->blocks->used_so_far]; pool->blocks->used_so_far += pool->element_size; pool->allocated_elements += 1; return element; } } }