exponenta event banner

CERT C: MEM35-C правил

Выделение достаточного объема памяти для объекта

Описание

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

Выделение достаточного объема памяти для объекта. [1 ]

Внедрение Polyspace

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

  • Доступ указателя выходит за границы.

  • Выделение памяти с запятнанным размером.

  • Неверный тип, используемый в sizeof при выделении памяти

Примеры

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

Проблема

Доступ к указателю вне границ происходит, когда указатель обнуляется за пределами его границ.

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

Риск

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

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

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

  • Верхняя граница цикла слишком велика.

  • Для продвижения указателя с неправильным значением приращения указателя использовалась арифметика указателя.

Чтобы устранить проблему, необходимо изменить ограничение цикла или значение приращения указателя.

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

См. примеры исправлений ниже.

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

Пример - Ошибка доступа указателя за пределами границ
int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i;
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr назначается адрес arr указывает на блок памяти размера 10*sizeof(int). В for-луп, ptr увеличивается в 10 раз. В последней итерации цикла ptr точки за пределами назначенного ему блока памяти. Поэтому его нельзя обособлять.

Коррекция - Проверка того, что указатель остается в пределах границ

Одной из возможных корректировок является изменение порядка приращения и отмены привязки ptr.

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

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

Проблема

Выделение памяти с поврежденным размером проверяет функции выделения памяти, такие как calloc или malloc, для аргументов размера из необеспеченных источников.

Риск

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

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

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

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

int* bug_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = (int*)malloc(size);
    return p;
}

В этом примере: malloc ассигнует size байты памяти указателя p. Переменная size поступает от пользователя программы. Его значение не проверяется и может превышать объем доступной памяти. Если size превышает количество доступных байтов, возможно сбой программы.

Исправление - Проверка размера выделяемой памяти

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

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

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

int* corrected_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = NULL;
    if (size>0 && size<SIZE128) {          /* Fix: Check entry range before use */
        p = (int*)malloc((unsigned int)size);
    }
    return p;
}
Проблема

Неправильный тип, используемый в sizeof при выделении памяти, возникает при использовании указателя в качестве аргумента sizeof вместо использования объекта, на который указывает указатель, при динамическом выделении памяти указателю. Например, эта проблема возникает при использовании malloc(sizeof(type*)) вместо malloc(sizeof(type)) при инициализации type* указатель.

Риск

Независимо от того, что type обозначает выражение, sizeof(type*) всегда возвращает размер указателя на платформе в байтах. При непреднамеренном использовании sizeof(type*) вместо sizeof(type) в вашем malloc оператор, выделенный блок памяти может быть меньше необходимого. Эта ошибка может привести к таким дефектам, как переполнение буфера.

Рассмотрим структуру structType, который содержит 10 int переменные. При инициализации structType* указатель с помощью malloc(sizeof(structType*)) на 32-битной платформе указателю назначается блок памяти размером четыре байта. Этого блока памяти недостаточно для structType структура, которая требует как минимум 10 * sizeof(int) байт. Поскольку требуемый размер намного больше фактического выделенного размера, используйте structType* вместо structType в качестве аргумента sizeof приводит к переполнению.

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

При выделении блоков памяти для указателей используйте sizeof(type) вместо sizeof(type*).

Пример - Выделение структурного массива с помощью sizeof Оператор в malloc Заявление
#include <stdlib.h>
typedef struct user{
	long uid;
	long euid;
	int number;
	int address;
	int value;
} USER;

void Noncompliant(void) {
	USER* user_list;
	user_list = (USER*)malloc(sizeof(USER*) * 5);
	/*...*/
	free(user_list);

}

В этом примере память динамически выделяется для массива user_list который содержит пять экземпляров структуры USER. Для этого массива требуется не менее 50 байт памяти, поскольку для каждого элемента массива требуется не менее 10 байт памяти. В malloc заявление, USER* используется в качестве аргумента для sizeof оператор вместо USER, возможно, непреднамеренно. В результате размер выделенного блока памяти может составлять 20 байт, что значительно меньше требуемого объема памяти. Эта ошибка может привести к переполнению буфера.

Исправление - использовать правильный тип

Одной из возможных корректировок является использование типа объекта, на который указывает указатель, в качестве входных данных для sizeof. Например, использовать USER вместо USER* при выделении памяти для массива USER.

#include <stdlib.h>
typedef struct user{
	long uid;
	long euid;
	int number;
	int address;
	int value;
} USER;

void Compliant(void) {
	USER* user_list;
	user_list = (USER*)malloc(sizeof(USER) * 5);
	/*...*/
	free(user_list);

}

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

Группа: Правило 08. Управление памятью (MEM)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

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