CERT C++: MEM30-C

Не получайте доступ освобожденный память

Описание

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

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

Реализация Polyspace

Это средство проверки проверяет на:

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

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

Примеры

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

Проблема

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

Риск

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

Фиксация

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

Как лучшая практика, после того, как вы освободите блок памяти, присваивают соответствующий указатель на 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;
   }

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 после освобождения их. Проверяйте указатели на Нулевое значение прежде, чем попытаться получить доступ к памяти, сопоставленной с указателем. Таким образом вы защищены от доступа к освобожденному блоку.

Пример — освобождающий ранее освобожденный указатель
#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 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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