CERT C++: MEM35-C

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

Описание

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

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

Реализация Polyspace

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

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

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

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

Примеры

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

Проблема

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

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

Риск

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

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

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

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

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

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

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

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

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

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

Коррекция - Проверяйте размер выделяемой памяти

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

#include "stdlib.h"

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

int* corrected_taintedmemoryallocsize(int size) {
    int* p = NULL;
          /* Fix: Check entry range before use */
    if (size>0 && size<SIZE128) {
        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*). Кроме того, избегайте использования malloc или аналогичные команды выделения памяти, которые требуют, чтобы вы задали размер блока памяти, который будет выделен. Используйте new оператор для выделения памяти без указания размера и delete оператор для удаления памяти.

Пример - Выделение массива при помощи sizeof Оператор в malloc Оператор
#include <stdlib.h>
class USER{
	long uid;
	long euid;
	int number;
	int address;
	int value;
};


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>
class USER{
	long uid;
	long euid;
	int number;
	int address;
	int value;
};

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

}
Коррекция - Избегайте использования malloc

Другой возможной коррекцией является использование new и delete операторы для выделения памяти.

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

void Compliant(void) {
	USER* user_list = new USER[5];
	//...
	delete(user_list);
}

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

Группа: 06. Управление памятью (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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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