MISRA C++:2008 Rule 0-3-2

Если функция генерирует информацию об ошибке, эта информация об ошибке должна быть проверена

Описание

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

Если функция генерирует информацию об ошибке, эта информация об ошибке должна быть проверена.

Объяснение

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

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

  • void

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

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

Реализация Polyspace

Шашка вызывает нарушение, когда:

  • Вы вызываете чувствительные стандартные функции, которые возвращают информацию о возможных ошибках, и вы делаете одно из следующего:

    • Игнорируйте возврат значение.

      Вы просто не присваиваете возврату значение переменной или явным образом приводите возврат значение к void.

    • Используйте выход из функции (возвращаемое значение или переданный по ссылке аргумент), не проверяя возврата значение на ошибки.

    Проверка рассматривает функцию как чувствительную, если вызов функции подвержен отказу по таким причинам, как:

    • Исчерпанные системные ресурсы (для примера, при распределении ресурсов).

    • Изменены привилегии или разрешения.

    • Испорченные источники при чтении, записи или преобразовании данных из внешних источников.

    • Неподдерживаемые функции, несмотря на существующий API.

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

    • Установите привилегии (для примера, setuid)

    • Создайте тюрьму (для примера, chroot)

    • Создайте процесс (для примера, fork)

    • Создайте поток (для примера, pthread_create)

    • Блокируйте или разблокируйте мьютекс (для примера, pthread_mutex_lock)

    • Блокируйте или разблокируйте сегменты памяти (для примера, mlock)

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

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

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

    • fgetwc, strtol, и wcstol.

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

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

Поиск и устранение проблем

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

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

#include <pthread.h>
#include <cstdlib>
#define fatal_error() abort()

void initialize_1() {
    pthread_attr_t attr;
    pthread_attr_init(&attr); //Noncompliant
}

void initialize_2() {
    pthread_attr_t attr;
   (void)pthread_attr_init(&attr); //Compliant
}

void initialize_3() {
    pthread_attr_t attr;
    int result;
    result = pthread_attr_init(&attr); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

Этот пример показывает вызов чувствительной функции pthread_attr_init. Значение возврата pthread_attr_init игнорируется, вызывая нарушение правил.

Для соответствия можно явным образом привести возврат значение к void или протестируйте возвращаемое значение pthread_attr_init и проверяйте на ошибки.

#include <pthread.h>
#include <cstdlib>
#define fatal_error() abort()
extern void *start_routine(void *);

void returnnotchecked_1() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;

    (void)pthread_attr_init(&attr);
    (void)pthread_create(&thread_id, &attr, &start_routine, ((void *)0)); //Noncompliant
    pthread_join(thread_id,  &res); //Noncompliant
}

void returnnotchecked_2() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;
    int result;

    (void)pthread_attr_init(&attr);
    result = pthread_create(&thread_id, &attr, &start_routine, NULL); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

    result = pthread_join(thread_id,  &res); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

В этом примере вызываются две критические функции: pthread_create и pthread_join. Значение возврата pthread_create проигнорирован приведением к пустоте, но потому pthread_create является критической функцией (не просто чувствительной функцией), проверка правил все еще вызывает нарушение. Другая критическая функция, pthread_join, возвращает значение, которое игнорируется неявно.

Чтобы быть совместимым, проверьте возврат значение этих критических функций, чтобы проверить функцию, выполненную как ожидалось.

#include<cstdlib>
#include<cerrno>
#include<climits>
#include<iostream>

int main(int argc, char *argv[]) {
    char *str, *endptr;
    int base;
    
    str = argv[1];
    base = 10;
    
    long val = strtol(str, &endptr, base); //Noncompliant
    std::cout<<"Return value of strtol() = %ld\n" << val;
    
    errno = 0;
    long val2 = strtol(str, &endptr, base); //Compliant
    if((val2 == LONG_MIN || val2 == LONG_MAX) && errno == ERANGE) {
         std::cout<<"strtol error";
         exit(EXIT_FAILURE);
    }        
    std::cout<<"Return value of strtol() = %ld\n" << val2;
}

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

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

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

Группа: Языковые независимые вопросы
Категория: Требуемая
Введенный в R2020b