IssueMisuse of errno in a signal handler occurs when you
call one of these functions in a signal handler:
signal: You call the signal function
in a signal handler and then read the value of
errno.
For instance, the signal handler function handler calls
signal and then calls
perror, which reads
errno.
typedef void (*pfv)(int);
void handler(int signum) {
pfv old_handler = signal(signum, SIG_DFL);
if (old_handler == SIG_ERR) {
perror("SIGINT handler");
}
}errno-setting POSIX® function: You call an errno-setting
POSIX function in a signal handler but do not restore
errno when returning from the signal handler.
For instance, the signal handler function handler calls
waitpid, which changes
errno, but does not restore
errno before
returning.
#include <stddef.h>
#include <errno.h>
#include <sys/wait.h>
void handler(int signum) {
int rc = waitpid(-1, NULL, WNOHANG);
if (ECHILD != errno) {
}
}
RiskIn each case that the checker flags, you risk relying on an indeterminate value of
errno.
signal: If the call to signal in
a signal handler fails, the value of errno is
indeterminate (see C11 Standard, Sec. 7.14.1.1). If you rely on a
specific value of errno, you can see unexpected
results.
errno-setting POSIX function: An errno-setting function
sets errno on failure. If you read
errno after a signal handler is called and the
signal handler itself calls an errno-setting
function, you can see unexpected results.
FixAvoid situations where you risk relying on an indeterminate value of
errno.
signal: After calling the signal
function in a signal handler, do not read errno or
use a function that reads errno.
errno-setting POSIX function: Before calling an
errno-setting function in a signal handler, save
errno to a temporary variable. Restore
errno from this variable before returning from
the signal handler.
Example - Reading errno After signal Call in Signal
Handler#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#define fatal_error() abort()
void handler(int signum) {
if (signal(signum, SIG_DFL) == SIG_ERR) {
perror("SIGINT handler");
}
}
int func(void) {
if (signal(SIGINT, handler) == SIG_ERR) {
/* Handle error */
fatal_error();
}
/* Program code */
if (raise(SIGINT) != 0) {
/* Handle error */
fatal_error();
}
return 0;
}In this example, the function handler is called to handle the
SIGINT signal. In the body of handler, the
signal function is called. Following this call, the value of
errno is indeterminate. The checker raises a defect when the
perror function is called because perror
relies on the value of errno.
Correction — Avoid Reading errno After
signal CallOne possible correction is to not read errno after calling
the signal function in a signal handler. The corrected code
here calls the abort function via the
fatal_error macro instead of the
perror function.
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#define fatal_error() abort()
void handler(int signum) {
if (signal(signum, SIG_DFL) == SIG_ERR) {
fatal_error();
}
}
int func(void) {
if (signal(SIGINT, handler) == SIG_ERR) {
/* Handle error */
fatal_error();
}
/* Program code */
if (raise(SIGINT) != 0) {
/* Handle error */
fatal_error();
}
return 0;
}