A small dynamic memory fault injector for glibc linux systems written in C11.
It intercepts memory allocations (malloc, calloc, realloc, posix_memalign, aligned_alloc) at runtime via LD_PRELOAD. This allows you to deterministically simulate Out-Of-Memory (OOM) conditions to test how your application handles memory failures w/o modifying/recompiling any source code.
- Linux 2.6+
- glibc 2.30+
- GCC 4.9+ or Clang 3.6+
- CMake 3.20+
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildThis produces the shared library at build/libtrutisui.so.
Inject Trutisui shared library into any dynamically linked executable using the LD_PRELOAD env var.
Trutisui will start failing from the very first memory allocation.
LD_PRELOAD=/path/to/trutisui/build/libtrutisui.so ./my_appControl exactly when the fault start occuring using the TRUTISUI_FAIL_AFTER env var.
Useful when an app needs to run some startup code.
# Force my_app to start failing on its 100th memory allocation
TRUTISUI_FAIL_AFTER=100 LD_PRELOAD=/path/to/trutisui/build/libtrutisui.so ./my_appWhen Trutisui injects a fault, it logs a single line to stderr:
[trutisui] #15 tid=4892 FAIL malloc(1024) @ 0x55d8f61c205e
[trutisui] summary: 16 calls, 1 faults injected#15: The global sequence number across all threads (this was the 15th allocation requested by the app).tid=4892: The OS-level thread ID that requested the failing memory.FAIL malloc(1024): The type of allocation and requested params.@ 0x55d8f61c205e: The exact memory address of the caller in your binary.- Tip: Use
addr2line -e ./my_app 0x55d8f61c205eto find the exact file and line of source code that crashed.
- Tip: Use
#define _GNU_SOURCE
#include <stdlib.h>
int main(void) {
char *a = (char *)malloc(10);
char *b = (char *)calloc(1, 10);
char *c = (char *)realloc(a, 20);
void *d;
posix_memalign(&d, 16, 32);
void *e = aligned_alloc(16, 32);
return 0;
}We run the dummy app (compiled with O0 else the calls will be optimised away) with TRUTISUI_FAIL_AFTER=2.
This means the first 2 allocations (malloc and calloc) will succeed normally, but the 3rd (realloc), 4th (posix_memalign), and 5th (aligned_alloc) will be intercepted and forcibly failed.
$ TRUTISUI_FAIL_AFTER=2 LD_PRELOAD=/path/to/trutisui/build/libtrutisui.so ./dummy
[trutisui] #2 tid=776978 FAIL realloc(0x561fe66e805e, 20) @ 0x561fe66e806b
[trutisui] #3 tid=776978 FAIL posix_memalign(16, 32) @ 0x561fe66e807a
[trutisui] #4 tid=776978 FAIL aligned_alloc(16, 32) @ 0x561fe66e8089
[trutisui] summary: 5 calls, 3 faults injected