# What Happens When Memory Allocation Fails in mulle-allocator: Does It Always Exit?

> Discover what happens when memory allocation fails in mulle-allocator. Learn how to customize fail callbacks for graceful exit and recovery instead of program termination.

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

---

**When memory allocation fails in mulle-allocator, the default behavior aborts the program, but the library provides a customizable fail callback in `struct mulle_allocator` that allows applications to implement graceful exit, cleanup, or recovery strategies instead.**

The mulle-c/mulle-allocator library provides a flexible memory management framework where allocation failures trigger a user-configurable callback rather than forcing an immediate crash. Understanding how the library handles out-of-memory conditions is crucial for building robust C applications that can either terminate cleanly or attempt recovery when system resources are exhausted.

## Default Behavior: Abort on Allocation Failure

The library defines a default fail handler named `mulle_allocation_fail` that executes when any allocation routine cannot obtain memory from the system. According to the implementation in **[`src/mulle-allocator.c`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.c)** (lines 44-55), this handler prints a diagnostic message using `perror` and immediately invokes `abort()`, causing the program to terminate abnormally without stack unwinding or cleanup.

This default applies consistently across all allocator variants. When `mulle_malloc`, `mulle_calloc`, or `mulle_realloc` return NULL from the underlying system call, they automatically invoke the fail callback, ensuring that the program crashes predictably rather than continuing with invalid pointers.

```c
/* Default behaviour – abort on failure */
#include <mulle-allocator/mulle-allocator.h>

int main(void)
{
    /* This will invoke the built‑in fail handler on OOM */
    void *p = mulle_malloc(1UL << 40);   // request huge block
    (void)p;   // never reached
}

```

## Customizing the Fail Callback

Unlike standard library allocators, mulle-allocator exposes the fail callback as a public function pointer within `struct mulle_allocator`, enabling complete customization of failure handling. The test suite demonstrates this flexibility in **[`test/fails/fail-malloc.c`](https://github.com/mulle-c/mulle-allocator/blob/main/test/fails/fail-malloc.c)** (lines 6-10), where the default handler is replaced with a custom function that prints a message and calls `exit(0)` instead of aborting.

To override the default behavior, assign your custom function to `mulle_default_allocator.fail`. Your handler must match the signature `void fail(struct mulle_allocator *alloc, void *ptr, size_t size)`, receiving the allocator instance, the original pointer (for realloc failures), and the requested allocation size.

```c
/* Custom fail handler – graceful termination */
#include <mulle-allocator/mulle-allocator.h>
#include <stdio.h>
#include <stdlib.h>

static void my_fail(struct mulle_allocator *alloc, void *ptr, size_t size)
{
    fprintf(stderr, "Allocation of %zu bytes failed, exiting gracefully.\n", size);
    exit(EXIT_FAILURE);
}

int main(void)
{
    /* Install custom handler */
    mulle_default_allocator.fail = my_fail;

    /* This will call `my_fail` instead of aborting */
    void *p = mulle_malloc(1UL << 40);
    (void)p;   // never reached
}

```

## Implementation Details

The fail callback triggers immediately upon detection of a NULL return from the underlying system allocation. This design provides a centralized error handling path for all memory operations, ensuring that both new allocations via `mulle_malloc` and resize operations via `mulle_realloc` invoke the same failure logic. Because the callback receives the requested size and allocator context, handlers can implement sophisticated strategies such as logging memory pressure statistics, freeing cache buffers before retry, or signaling worker threads to reduce consumption.

## Summary

- **Default termination**: Failed allocations invoke `mulle_allocation_fail` in [`src/mulle-allocator.c`](https://github.com/mulle-c/mulle-allocator/blob/main/src/mulle-allocator.c), which prints an error and calls `abort()` to terminate the program immediately.
- **Customizable callback**: The `fail` member of `struct mulle_allocator` is a function pointer that applications can override to implement graceful shutdown, logging, or recovery.
- **Proven pattern**: The repository's [`test/fails/fail-malloc.c`](https://github.com/mulle-c/mulle-allocator/blob/main/test/fails/fail-malloc.c) demonstrates replacing the default handler with a custom function that calls `exit(0)` instead of aborting.
- **Universal coverage**: All allocator routines—including `mulle_malloc`, `mulle_calloc`, and `mulle_realloc`—invoke the same fail callback upon memory exhaustion.

## Frequently Asked Questions

### Does mulle-allocator always exit when memory allocation fails?

No. While the default implementation calls `abort()` through the `mulle_allocation_fail` handler, the library is explicitly designed to allow custom failure callbacks. You can replace the default with a handler that performs cleanup and calls `exit()` or even attempts recovery, as demonstrated in [`test/fails/fail-malloc.c`](https://github.com/mulle-c/mulle-allocator/blob/main/test/fails/fail-malloc.c).

### How do I install a custom allocation failure handler?

Assign your custom function to `mulle_default_allocator.fail`. Your handler must accept three parameters: a pointer to the `struct mulle_allocator`, the original pointer (relevant for realloc operations), and the requested size. The test suite provides a complete working example in [`test/fails/fail-malloc.c`](https://github.com/mulle-c/mulle-allocator/blob/main/test/fails/fail-malloc.c) (lines 6-10).

### What is the signature of the fail callback function?

The fail callback conforms to the signature `void fail(struct mulle_allocator *alloc, void *ptr, size_t size)`. The `ptr` parameter contains the original pointer when realloc fails, or NULL for malloc/calloc failures, while `size` indicates the number of bytes requested.

### Can I retry allocation inside the fail callback?

Technically yes, since the callback is arbitrary C code, but doing so risks infinite recursion if the retry also fails. The library places no restrictions on callback behavior, allowing retries, logging, or alternative memory strategies, though most implementations choose to terminate or cleanup according to the source analysis.