A signal handler is allowed to call signal()
, and if that fails, signal()
returns SIG_ERR
and sets errno
to a positive value. However, if the event that caused a signal was external (not as the result of the program calling abort()
or raise()
), the signal handler must only call _Exit()
or abort()
, or call signal()
on the signal currently being handled, and if signal()
fails, the value of errno
is indeterminate.
This rule is a special case of SIG31-C. Do not access or modify shared objects in signal handlers. The object designated by errno
is of static storage duration and is not a volatile sig_atomic_t
. As a result, performing any action that would require errno
to be set would normally cause undefined behavior. The C standard makes a special exception for errno
in this case, saying the only thing that is allowed to go wrong is that errno
takes on an indeterminate value. This makes it possible to call signal()
from within a signal handler without risking completely unrestricted undefined behavior, but the handler, and any code executed after the handler returns, must not depend on the value of errno
being meaningful.
Non-Compliant Code Example
If the request to register a signal handler set the signal to default can be honored, the signal()
function returns the value of the signal handler for the most recent successful call to the signal()
function for the specified signal. Otherwise, a value of SIG_ERR
is returned and a positive value is stored in errno
.
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdlib.h> #include <string.h> typedef void (*pfv)(int); void handler(int signum) { pfv old_handler = signal(signum, handlerSIG_DFL); if (old_handler == SIG_ERR) { perror("SIGINT handler"); /* undefined behavior */ /* handle error condition */ } } int main(void) { pfv old_handler = signal(SIGINT, handler); if (old_handler == SIG_ERR) { perror("SIGINT handler"); /* handle error condition */ } /* main code loop */ return 0; } |
...
The compliant solution does not reference errno
, and does not return from the signal handler if the signal()
call fails.
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdlib.h> #include <string.h> typedef void (*pfv)(int); void handler(int signum) { pfv old_handler = signal(signum, handlerSIG_DFL); if (old_handler == SIG_ERR) { /* handle error condition */abort(); } } int main(void) { pfv old_handler = signal(SIGINT, handler); if (old_handler == SIG_ERR) { perror("SIGINT handler"); /* handle error condition */ } /* main code loop */ return 0; } |
...