# Difference Between mulle_realloc and mulle_realloc_strict in Mulle-Allocator

> Understand the difference between mulle_realloc and mulle_realloc_strict. Learn how they handle zero-size requests to prevent memory leaks and ensure standard C realloc behavior for robust memory management.

- Repository: [mulle-c/mulle-allocator](https://github.com/mulle-c/mulle-allocator)
- Tags: deep-dive
- Published: 2026-03-07

---

**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`](https://github.com/mulle-c/mulle-allocator/blob/main/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`](https://github.com/mulle-c/mulle-allocator/blob/main/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_realloc`** uses the inline wrapper `mulle_allocator_realloc` defined in [`src/mulle-allocator.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h) (lines 370–376), which immediately calls the allocator's function pointer.

- **`mulle_realloc_strict`** uses `_mulle_allocator_realloc_strict` in [`src/mulle-allocator.c`](https://github.com/mulle-c/mulle-allocator/blob/main/src/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`](https://github.com/mulle-c/mulle-allocator/blob/main/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

```c
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

```c
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

```c
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_realloc`** passes size zero directly to the allocator's `realloc` callback, leaving the original block allocated and potentially causing memory leaks
- **`mulle_realloc_strict`** explicitly frees the memory block when resizing to zero, returning NULL and preventing resource leaks
- Both functions invoke `_mulle_allocator_fail` if the underlying reallocation returns NULL
- The strict variant is implemented in [`src/mulle-allocator.c`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.c) (lines 82–91), while the non-strict inline wrapper resides in [`src/mulle-allocator.h`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h) (lines 372–376)
- Prefer `mulle_realloc_strict` unless 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`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.h) at lines 372–376. `mulle_realloc_strict` is implemented in [`src/mulle-allocator.c`](https://github.com/mulle-c/mulle-allocator/blob/main/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.