CERT C: Rule ERR30-C

Обнулите errno прежде, чем вызвать библиотечную функцию, которая, как известно, установила errno и проверять errno только после того, как функция возвратит отказ указания значения

Описание

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

Обнулите errno прежде, чем вызвать библиотечную функцию, которая, как известно, установила errno и проверять errno только после того, как функция возвратит значение, указывающее failure.[1]

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

  • Неправильное употребление errno.

  • Errno не сброс.

Примеры

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

Проблема

Неправильное употребление errno происходит, когда вы проверяете errno для состояния ошибки в ситуациях, где проверка errno не гарантирует отсутствия ошибок. В некоторых случаях, проверка errno может привести к ложным положительным сторонам.

Например, вы проверяете errno следующие вызовы функций:

  • fopen: Если вы следуете Стандарту ISO®, функциональная сила не установила errno при ошибках.

  • atof: Если вы следуете стандарту ISO, функция не устанавливает errno.

  • signal: errno значение указывает на ошибку, только если функция возвращает SIG_ERR ошибочный индикатор.

Риск

Стандарт ISO C не осуществляет это, эти функции устанавливают errno при ошибках. Устанавливают ли функции errno или не является зависящим от реализации.

Обнаружить ошибки, если вы проверяете errno один, валидность этой проверки также становится зависящей от реализации.

В некоторых случаях, errno значение указывает на ошибку, только если функция возвращает определенный ошибочный индикатор. Если вы проверяете errno прежде, чем проверять функциональное возвращаемое значение, вы видите ложные положительные стороны.

Фиксация

Для получения информации о том, как обнаружить ошибки, см. документацию для той определенной функции.

Как правило, функции возвращают внеполосный ошибочный индикатор, чтобы указать на ошибки. Например:

  • fopen возвращает нулевого указателя, если ошибка происходит.

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

Пример - неправильно проверяющий на errno После fopen Вызвать
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define fatal_error() abort()

const char *temp_filename = "/tmp/demo.txt";

FILE *func()
{
    FILE *fileptr;
    errno = 0;
    fileptr = fopen(temp_filename, "w+b");
    if (errno != 0) {
        if (fileptr != NULL) {
            (void)fclose(fileptr);
        }
        /* Handle error */
        fatal_error();
    }
    return fileptr;
}

В этом примере, errno первая переменная, которая проверяется после вызова fopen. Вы можете ожидать тот fopen изменения errno к ненулевому значению, если ошибка происходит. Если при запуске этот код с реализацией fopen это не устанавливает errno при ошибках вы можете пропустить состояние ошибки. В этой ситуации, fopen может возвратить нулевого указателя, который выходит из обнаружения.

Коррекция — проверяет возвращаемое значение fopen После вызова

Одна возможная коррекция должна только проверять возвращаемое значение fopen для нулевого указателя.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define fatal_error() abort()

const char *temp_filename = "/tmp/demo.txt";

FILE *func()
{
    FILE *fileptr;
    fileptr = fopen(temp_filename, "w+b");
    if (fileptr == NULL) { 
        fatal_error();
    }
    return fileptr;
}
Проблема

Errno не сбрасывают, происходит, когда вы не сбрасываете errno прежде, чем вызвать функцию, которая устанавливает errno указать на состояние ошибки. Однако вы проверяете errno для того состояния ошибки после вызова функции.

Риск

errno не является чистым и может содержать значения от предыдущего вызова. Проверка errno поскольку ошибки могут произвести ложное впечатление, что ошибка произошла.

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

Фиксация

Прежде, чем вызвать функцию, которая устанавливает errno чтобы указать на состояние ошибки, сбросьте errno обнулять явным образом.

Пример - errno Не сброс перед вызовом strtod
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>

#define fatal_error() abort()

double func(const char *s1, const char *s2)
{
    double f1;
    f1 = strtod (s1, NULL);      
    if (0 == errno) {        
      double f2 = strtod (s2, NULL); 
        if (0 == errno) {        
            long double result = (long double)f1 + f2;
            if ((result <= (long double)DBL_MAX) && (result >= (long double)-DBL_MAX)) 
				  {
                return (double)result;
            }
        }
    }
    fatal_error();
    return 0.0;
}

В этом примере, errno не сбрасывается к 0 перед первым вызовом strtod. Проверка errno для 0 позже может привести к положительной лжи.

Коррекция — сброс errno Перед вызовом

Одна возможная коррекция должна сбросить errno к 0 прежде, чем вызвать strtod.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>

#define fatal_error() abort()

double func(const char *s1, const char *s2)
{
    double f1;
    errno = 0;                   
    f1 = strtod (s1, NULL);
    if (0 == errno) {            
      double f2 = strtod (s2, NULL);  
        if (0 == errno) {       
            long double result = (long double)f1 + f2;
            if ((result <= (long double)DBL_MAX) && (result >= (long double)-DBL_MAX)) 
  			{
                return (double)result;
            }
        }
    }
    fatal_error();
    return 0.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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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