Can exit() fail to terminate process?

Yes, there are some circumstances, such as:

The exit() function shall first call all functions registered by atexit(), in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered. Each function is called as many times as it was registered. If, during the call to any such function, a call to the longjmp() function is made that would terminate the call to the registered function, the behavior is undefined.

If a function registered by a call to atexit() fails to return, the remaining registered functions shall not be called and the rest of the exit() processing shall not be completed. If exit() is called more than once, the behavior is undefined.

See the POSIX page on exit.

For more information, attach a debugger when you reach the situation and take a look at the call stack.


Are you calling exit() from the signal handler?

In man 7 signal, section Async-signal-safe functions you can see all the functions that are guaranteed to work when called from an signal handler:

A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the program is undefined.

POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to guarantee that the following functions can be safely called inside a signal handler:

There you can see functions _Exit(), _exit() and abort(), but notably not exit(). So you should not call it from a signal handler.

The nasty thing is that even if you call an unsafe function from a signal handler (printf() any?) it will just work most of the time... but not always.