Difference Between mulle_realloc and mulle_realloc_strict in Mulle-Allocator
The critical difference between mulle_realloc and mulle_realloc_strict is their handling of zero-size requests: mulle_realloc calls the allocator's realloc directly without freeing the original block (risking memory leaks), while mulle_realloc_strict explicitly frees the memory and returns NULL, matching standard C realloc behavior.
The mulle-c/mulle-allocator library provides flexible memory management primitives for C applications. When resizing dynamically allocated memory, choosing the correct reallocation function prevents resource leaks and undefined behavior. This article examines the specific behavioral divergence between these two APIs and their implementation in the source code.
Zero-Size Reallocation Behavior
The distinction becomes critical when requesting a resize to zero bytes. Both functions wrap the allocator's internal callbacks, but they implement different strategies for this edge case.
mulle_realloc: Direct Pass-Through
mulle_realloc forwards the size parameter directly to the allocator's realloc callback without preprocessing. When size == 0, the underlying realloc implementation determines the outcome—either returning NULL or a valid pointer—but crucially, the original memory block remains allocated.
As documented in src/mulle-allocator.h at lines 372–376, this function "reallocs, but doesn't free. If you pass in size 0, you risk failing." If the allocator's realloc returns NULL, the allocator invokes _mulle_allocator_fail, which aborts the program by default.
mulle_realloc_strict: Safe Free-and-NULL Semantics
mulle_realloc_strict guarantees standard C realloc semantics. When size == 0, it explicitly calls (*p->free)(block, p) to release the original memory before proceeding. The function returns NULL for zero-size requests, ensuring no memory leak occurs.
This implementation appears in src/mulle-allocator.c at lines 82–91. Like its counterpart, it invokes the allocator's fail callback if reallocation fails, but only after properly freeing the original block when shrinking to zero.
Implementation Details
The source code reveals the architectural difference:
-
mulle_reallocuses the inline wrappermulle_allocator_reallocdefined insrc/mulle-allocator.h(lines 370–376), which immediately calls the allocator's function pointer. -
mulle_realloc_strictuses_mulle_allocator_realloc_strictinsrc/mulle-allocator.c(lines 82–91), which checks for zero size and performs an explicit free operation before reallocation.
Both functions rely on the allocator structure defined in src/mulle-allocator-struct.h, which specifies the function pointers for realloc, free, and failure handling callbacks.
Practical Code Examples
Risky Usage with mulle_realloc
void *buffer = mulle_malloc(128);
/* Dangerous: size 0 does NOT free the original 128 bytes */
buffer = mulle_realloc(buffer, 0);
/* Original memory is potentially leaked here if realloc returned NULL
* or a new zero-length pointer */
Safe Zero-Size Handling with mulle_realloc_strict
void *buffer = mulle_malloc(128);
/* Safe: explicitly frees the block and returns NULL */
buffer = mulle_realloc_strict(buffer, 0);
assert(buffer == NULL); /* Guaranteed behavior */
Normal Growth Operations
void *data = mulle_malloc(64);
/* Both functions behave identically for non-zero sizes */
data = mulle_realloc(data, 256); /* Grow to 256 bytes */
data = mulle_realloc_strict(data, 512); /* Further grow to 512 bytes */
Which Function Should You Use?
Use mulle_realloc_strict for the majority of reallocation scenarios, especially when:
- You expect zero-size requests to release memory (standard C semantics)
- You want predictable behavior matching
realloc(3) - You cannot risk leaking memory due to allocator-specific zero-size handling
Use mulle_realloc only when you specifically require the allocator's native zero-size behavior, such as when working with custom allocators that define specific semantics for zero-byte allocations. This is rare in typical application code.
Summary
mulle_reallocpasses size zero directly to the allocator'srealloccallback, leaving the original block allocated and potentially causing memory leaksmulle_realloc_strictexplicitly frees the memory block when resizing to zero, returning NULL and preventing resource leaks- Both functions invoke
_mulle_allocator_failif the underlying reallocation returns NULL - The strict variant is implemented in
src/mulle-allocator.c(lines 82–91), while the non-strict inline wrapper resides insrc/mulle-allocator.h(lines 372–376) - Prefer
mulle_realloc_strictunless you have specific requirements for the allocator's native zero-size behavior
Frequently Asked Questions
What happens when mulle_realloc is called with size 0?
mulle_realloc calls the allocator's realloc function pointer with the zero size parameter. The original memory block is not freed beforehand, meaning the allocator may either return NULL or a valid pointer, but the original allocation remains active. This can result in a memory leak if the caller loses the reference to the original block.
Does mulle_realloc_strict follow standard C realloc semantics?
Yes. mulle_realloc_strict implements the standard C library behavior where passing size zero to realloc first frees the original memory block and returns NULL. This ensures predictable resource management and prevents the memory leaks possible with the non-strict variant.
Where are these functions defined in the mulle-allocator source?
mulle_realloc is defined as an inline function in src/mulle-allocator.h at lines 372–376. mulle_realloc_strict is implemented in src/mulle-allocator.c at lines 82–91 as _mulle_allocator_realloc_strict, which the public API wraps.
Can mulle_realloc cause memory leaks?
Yes. If you call mulle_realloc with a size of zero and the allocator's underlying realloc implementation returns NULL or a new pointer without freeing the original block, the original memory remains allocated but becomes unreachable if you overwrite your pointer variable with the return value. Always use mulle_realloc_strict when zero-size reallocation might occur.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →