When you want to set signal handlers on UNIX systems, the typical choice is to use signal
(specified in C89, C99 and POSIX.1-2001) or sigaction
(specified in POSIX.1-2001 and System V r4).
Quoting the signal
manual page:
The only portable use of signal()
is to set a signal's disposition to SIG_DFL or SIG_IGN
. The semantics when using signal()
to establish a signal handler vary across systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.
POSIX.1 solved the portability mess by specifying sigaction(2)
, which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal()
.
Then it goes on about the UNIX vs BSD semantics, and how they affect signal delivery, which essentially is the main reason why one would want to stop using signal
and use sigaction
instead, with specifically chosen flags.
But this is not really what I wanted to talk about here.
One of the uses of signal
or sigaction
is to temporarily set a signal handler and restore the old signal handler once the job is done. Notwithstanding the fact that it's a pretty horrible thing to do in a multi-threaded program, it's also a horrible thing to do at all with signal
if sigaction
is used.
The core of the problem is the following: the information you get from signal()
about the old signal handler is missing all the important pieces about it if it was originally set with sigaction()
, namely, flags, masks and restorer.
So if you do use signal()
to temporarily set a signal handler and then restore the previous signal handler, you risk resetting flags, masks and restorer. The first awful thing this means is the previous signal handler might be expecting three arguments, only one of which will be valid when it's invoked. Unexpected things can also happen with the lack of expected flags or masks. This is why you'll see horrible workarounds like this or that.
In short, if you do use signal()
to temporarily set a signal handler and then restore the previous signal handler, you're doing it wrong. And if you do that in a system library or driver, thank you for screwing things up. I'm looking at you libsc-a3xx.so
.