In this lesson, you will learn why calling certain C library functions inside a signal handler can crash your entire program.
The Asynchronous Surprise
When a signal is delivered to your process, the kernel interrupts the current execution flow to run your signal handler. Crucially, this can happen at any moment—even if your program is currently in the middle of executing a complex function like malloc() or printf().
If your signal handler calls that same function while the main program is still halfway through it, you trigger the reentrancy problem.
Why Reentrancy Matters
A function is "reentrant" if it can be safely interrupted and called again before the first invocation finishes. Most functions in the standard C library are not reentrant because they often rely on shared internal state.
Imagine your main program is busy updating a global buffer inside printf(). Suddenly, a signal fires, and your handler calls printf() again. The internal pointers and memory states of the library get corrupted because two instances of the same function are fighting over the same data. The result? Your program might deadlock, crash with a segmentation fault, or experience silent data corruption.
A Dangerous Example
Look at this problematic pattern:
void my_handler(int sig) {
// DANGER: printf() is NOT async-signal-safe!
printf("Signal received!\n");
}
If the main program was in the middle of a printf() call when the signal arrived, the handler tries to use the same internal buffers managed by printf(). Since printf() is not reentrant, the output might become garbled, or the program might hang forever because the internal locks used by printf() are now stuck in an inconsistent state.
How to Stay Safe
To avoid these issues, only call functions that are "async-signal-safe." These are functions explicitly designed to handle being interrupted (like write() or _exit()). If you need to perform complex logic, set a simple volatile sig_atomic_t flag inside your handler and process the data in your main loop instead.
Key Takeaway: Never call non-reentrant functions inside a signal handler, as they can cause unpredictable crashes by interrupting the very data structures they are currently modifying.