Misuse of errno in a signal handler

Читаешь errno после вызова errno-настройка функции в обработчике сигналов

Описание

Этот дефект возникает, когда вы вызываете одну из следующих функций в обработчике сигнала:

  • signal: Вы вызываете signal функция в обработчике сигналов и затем считывание значения errno.

    Например, функция обработчика сигналов handler вызывает signal а затем вызывает perror, который читается 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-настройка POSIX® функция: Вы вызываете errno- установка функции POSIX в обработчике сигналов, но не восстановление errno при возвращении с обработчика сигнала.

    Например, функция обработчика сигналов handler вызывает waitpid, который изменяет errno, но не восстанавливает errno перед возвращением.

    #include <stddef.h>
    #include <errno.h>
    #include <sys/wait.h>
    
    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: An errno-настройка наборов функций errno при отказе. Если вы читаете errno после того, как вызывается обработчик сигнала, и сам обработчик сигнала вызывает errno-настройка функции, вы можете увидеть неожиданные результаты.

Зафиксировать

Избегайте ситуаций, когда вы рискуете полагаться на неопределенное значение errno.

  • signal: После вызова signal не считывайте функцию в обработчике сигналов errno или используйте функцию, которая читает errno.

  • errno-настройка функции POSIX: перед вызовом errno-настройка функции в обработчике сигнала, сохранение errno во временную переменную. Восстановление errno от этой переменной до возврата с обработчика сигнала.

Примеры

расширить все

#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;
}

Информация о результатах

Группа: Программирование
Язык: C | C++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки : SIG_HANDLER_ERRNO_MISUSE
Влияние: Средний
Введенный в R2018a