CERT C: правило ERR32-C

Не полагайтесь на неопределенные значения errno

Описание

Управляйте определением

Не полагайтесь на неопределенные значения errno. [1]

Примеры

развернуть все

Описание

Неправильное употребление 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 на отказе. Если вы читаете 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;
}

Проверяйте информацию

Группа: правило 12. Обработка ошибок (ERR)

Введенный в R2019a


[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.