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

Обнаружьте и обработайте стандартные ошибки библиотеки

Описание

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

Обнаружьте и обработайте стандартные ошибки библиотеки. [1]

Примеры

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

Описание

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

Описание

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

  • Проигнорируйте возвращаемое значение.

  • Используйте вывод или возвращаемое значение, не тестируя валидность возвращаемого значения.

Для этого дефекта рассматриваются два типа функций: чувствительный и очень важный чувствительный.

Чувствительная функция является стандартной функцией, которая может столкнуться:

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

  • Измененные привилегии или полномочия

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

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

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

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

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

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

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

  • Заблокируйте или разблокируйте взаимное исключение (например, pthread_mutex_lock)

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

Риск

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

Фиксация

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

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

Пример - чувствительный функциональный проигнорированный возврат

#include <pthread.h>

void initialize() {
    pthread_attr_t attr;

    pthread_attr_init(&attr); 
}

Этот пример показывает вызов чувствительного функционального pthread_attr_init. Возвращаемое значение pthread_attr_init проигнорировано, вызвав дефект.

Исправление — функция броска к (void)

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

#include <pthread.h>

void initialize() {
    pthread_attr_t attr;

    (void)pthread_attr_init(&attr); 
}

Исправление — тестирует возвращаемое значение

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

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

void initialize() {
    pthread_attr_t attr;
    int result;

    result = pthread_attr_init(&attr);
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

Пример - критический функциональный проигнорированный возврат

#include <pthread.h>
extern void *start_routine(void *);

void returnnotchecked() {
    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));
    pthread_join(thread_id,  &res); 
}

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

Исправление — тестирует возвращаемое значение критических функций

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

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

extern void *start_routine(void *);

void returnnotchecked() {
    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);
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

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

Описание

Незащищенное динамическое выделение памяти происходит, когда вы не проверяете после динамического выделения памяти ли выделение памяти, за которым следуют.

Риск

Когда память динамически выделяется с помощью malloc, calloc или realloc, это возвращает значение NULL, если требуемая память не доступна. Если код после выделения получает доступ к блоку памяти, не проверяя на это значение NULL, этот доступ не защищен от отказов.

Фиксация

Проверяйте возвращаемое значение malloc, calloc или realloc для NULL прежде, чем получить доступ к выделенной ячейке памяти.

int *ptr = malloc(size * sizeof(int));

if(ptr) /* Check for NULL */ 
{
   /* Memory access through ptr */
}

Пример - Незащищенная ошибка динамического выделения памяти

#include <stdlib.h>

void Assign_Value(void) 
{
  int* p = (int*)calloc(5, sizeof(int));

  *p = 2;  
  /* Defect: p is not checked for NULL value */

  free(p);
}

Если выделение памяти перестало работать, функциональный calloc возвращает NULL в p. Прежде, чем получить доступ к памяти через p, код не проверяет, является ли p NULL

Исправление — проверяет на нулевое значение

Одно возможное исправление должно проверять, имеет ли p значение, которое прежде разыменовывает NULL.

#include <stdlib.h>

void Assign_Value(void)
 {
   int* p = (int*)calloc(5, sizeof(int));

   /* Fix: Check if p is NULL */
   if(p!=NULL) *p = 2; 

   free(p);
 }

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

Группа: правило 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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