CERT C++: MEM30-C

Не получайте доступ к свободной памяти

Описание

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

Не получайте доступ к свободной памяти.[1]

Реализация Polyspace

Эта проверка проверяет:

  • Доступ к ранее освобожденному указателю

  • Освобождение ранее освобожденного указателя

Примеры

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

Проблема

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

Риск

Когда указателю выделяется динамическая память при помощи malloc, calloc или realloc, это указывает на место памяти на куче. Когда вы используете free функция на этом указателе, связанный блок памяти освобождается для перераспределения, и указатель становится болтающимся указателем. Попытка получить доступ к этому блоку памяти путем дереферирования болтающегося указателя может привести к непредсказуемому поведению или отказу сегментации.

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

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

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

Пример - Доступ к ранее освобожденной ошибке указателя
#include <stdlib.h>
#include <stdio.h>
 int increment_content_of_address(int base_val, int shift)
   { 
    int j;
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return 0;

    *pi = base_val;
    free(pi);

    j = *pi + shift;
    /* Defect: Reading a freed pointer */
 
    return j;
   }

The free оператор освобождает блок памяти, который pi относится к. Поэтому разыменование pi после free недопустимый оператор.

Коррекция - Свободный указатель после последнего использования

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

#include <stdlib.h>

int increment_content_of_address(int base_val, int shift)
{
    int j;
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return 0;

    *pi = base_val;

    j = *pi + shift;
    *pi = 0;

    /* Fix: The pointer is freed after its last use */
    free(pi);               
    return j;
}
Проблема

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

Риск

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

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

Чтобы избежать этого дефекта, присвойте указатели NULL после освобождения. Перед попыткой получить доступ к памяти, связанной с указателем, проверьте указатели на значение NULL. Таким образом, вы защищены от доступа к освобожденному блоку.

Пример - Освобождение ранее освобожденного указателя
#include <stdlib.h>
#include <stdio.h>
int getStatus();
void double_deallocation(void)
{
	int* pi = (int*)malloc(sizeof(int));
	if (pi == 0) return;

	*pi = 2;
	/*...*/
	if(getStatus()==1)
	{
		/*...*/
		free(pi);
	}
	free(pi); //Noncompliant
}

Вторая free оператор пытается освободить блок памяти, который pi ссылается на, но указатель pi возможно, уже будет освобожден в if блок кода. Этот второй free оператор может вызвать утечку памяти и уязвимости безопасности в коде. Polyspace® флаги второго free оператор.

Коррекция - контрольные указатели перед вызовом free

Одной из возможных коррекций является назначение свободных указателей NULL и проверка указателей на NULL перед их освобождением.

#include <stdlib.h>
#include <stdio.h>
int getStatus();
void double_deallocation(void)
{
	int* pi = (int*)malloc(sizeof(int));
	if (pi == 0) return;

	*pi = 2;
	/*...*/
	if(getStatus()==1)
	{
		/*...*/
		if(pi!=NULL)
		{
			free(pi);
			pi= NULL;
		}
	}
	/*...*/
	if(pi!=NULL)
	{
		free(pi);
		pi= NULL;
	} //Compliant
}

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

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

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

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

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