Проблема
Неправильное употребление errno в обработчике сигнала происходит, когда вы вызываете одну из этих функций в обработчике сигнала:
signal
: Вы вызываете signal
функция в обработчике сигнала и затем считала значение errno
.
Например, функция-обработчик сигнала handler
вызовы signal
и затем вызовы perror
, который читает errno
.
void handler(int signum) {
pfv old_handler = signal(signum, SIG_DFL);
if (old_handler == SIG_ERR) {
perror("SIGINT handler");
}
}
errno
- установка функции POSIX®: Вы вызываете errno
- функция установки POSIX в обработчике сигнала, но не восстанавливает errno
при возврате из обработчика сигнала.
Например, функция-обработчик сигнала handler
вызовы waitpid
, который изменяет errno
, но не восстанавливает errno
перед возвратом.
void handler(int signum) {
int rc = waitpid(-1, NULL, WNOHANG);
if (ECHILD != errno) {
}
}
Риск
В каждом случае, который отмечает средство проверки, вы рискуете использовать неопределенное значение errno
.
signal
: Если вызов signal
в обработчике сигнала перестал работать, значение errno
неопределенно (см. Стандарт C11, Секунда. 7.14.1.1). Если вы используете определенное значение errno
, вы видите неожиданные результаты.
errno
- функция установки POSIX: errno
- установка функции устанавливает errno
onFailure. Если вы читаете errno
после того, как обработчик сигнала называется, и сам обработчик сигнала вызывает errno
- устанавливая функцию, вы видите неожиданные результаты.
Фиксация
Избегайте ситуаций, где вы рискуете использовать неопределенное значение errno
.
signal
: После вызова signal
функция в обработчике сигнала, не читайте errno
или используйте функцию, которая читает errno
.
errno
- функция установки POSIX: Прежде, чем вызвать errno
- установка функции в обработчике сигнала, сохраните errno
к временной переменной. Восстановите errno
от этой переменной прежде, чем возвратиться из обработчика сигнала.
Пример - чтение errno
После signal
Вызовите в обработчике сигнала
#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;
}
В этом примере, функциональном handler
называется, чтобы обработать SIGINT
сигнал. В теле handler
, signal
функция вызвана. После этого вызова, значения errno
неопределенно. Средство проверки повышает дефект когда perror
функция вызвана потому что perror
использует значение errno
.
Коррекция — старается не читать errno
После signal
Вызвать
Одна возможная коррекция не должна читать errno
после вызова signal
функция в обработчике сигнала. Исправленный код здесь вызывает abort
функция через fatal_error
макрос вместо perror
функция.
#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;
}