exponenta event banner

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

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 освобождается, только если он еще не освобожден.

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

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

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

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