CERT C: Rule ERR30-C

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

Описание

Определение правила

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

Реализация Polyspace

Эта проверка проверяет на наличие следующих проблем:

  • Неправильное использование errno.

  • Errno не сбрасывается.

Примеры

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

Проблема

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

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

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

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

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

Риск

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

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

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

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

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

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

  • fopen возвращает указатель null, если произошла ошибка.

  • 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 для указателя со значением null.

#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 not сброс происходит, когда вы не сбрасываете errno перед вызовом функции, которая устанавливает errno для указания условий ошибки. Однако вы проверяете errno для условий ошибки после вызова функции.

Риск

The 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 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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