ISO/IEC TS 17961 [inverrno]

Неправильная настройка и использование 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 не проверяется, когда вы вызываете функцию, которая устанавливает errno чтобы указать условия ошибки, но не проверяйте errno после вызова. Для этих функций проверяйте errno является единственным надежным способом определить, произошла ли ошибка.

Функции, которые задают errno при ошибках включают:

  • fgetwc, strtol, и wcstol.

    Полный список функций см. в документации об errno.

  • POSIX® errno-настройка функций, таких как encrypt и setkey.

Риск

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

Значения возврата этих errno-настройка функций не указывает на ошибки. Значение возврата может быть одним из следующих:

  • void

  • Даже если происходит ошибка, возврат значение может быть таким же, как значение от успешного вызова. Такие возвращаемые значения называются внутриполосными индикаторами ошибок.

Определить, произошла ли ошибка, можно только проверив errno.

Для образца, strtol преобразует строку в длинное целое число и возвращает целое число. Если результат преобразования переполнен, функция возвращается LONG_MAX и устанавливает errno на ERANGE. Однако функция также может вернуться LONG_MAX от успешного преобразования. Только проверяя errno можно ли различать ошибку и успешное преобразование.

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

Перед вызовом функции установите errno в нуль.

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

Сообщение об ошибке в Polyspace® результат показывает значение индикатора ошибки, с которым можно сравнить.

Пример - errno Не проверено после вызова в strtol
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

int main(int argc, char *argv[]) {
    char *str, *endptr;
    int base;
    
    str = argv[1];
    base = 10;
    
    long val = strtol(str, &endptr, base);
    printf("Return value of strtol() = %ld\n", val);
}

Вы используете возврат значение strtol без проверки errno.

Коррекция - Проверяйте errno После вызова

Перед вызовом strtol, задать errno в нуль. После вызова к strtol, проверьте значение возврата на LONG_MIN или LONG_MAX и errno для ERANGE.

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

int main(int argc, char *argv[]) {
    char *str, *endptr;
    int base;
    
    str = argv[1];
    base = 10;
    
    errno = 0;
    long val = strtol(str, &endptr, base);
    if((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
         printf("strtol error");
         exit(EXIT_FAILURE);
    }        
    printf("Return value of strtol() = %ld\n", val);
}
Проблема

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

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

Решимость: Undecidable
Введенный в R2019a

[1] Выдержки из стандарта «Техническая спецификация ISO/IEC TS 17961 - 2013-11-15» воспроизводятся с согласия АФНОР. Только оригинальный и полный текст стандарта, опубликованный AFNOR Editions - доступный через веб-сайт www.boutique.afnor.org - имеет нормативное значение.