exponenta event banner

CERT C++: MEM50-CPP

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

Описание

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

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

Внедрение Polyspace

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

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

  • Отмена назначения ранее отмененного указателя.

  • Использование ранее освобожденного указателя.

Примеры

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

Проблема

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

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

Риск

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

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

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

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

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

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

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

Проблема

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

Риск

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

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

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

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

Пример - Отмена назначения ранее отмененного указателя
#include <stdlib.h>

void allocate_and_free(void)
{

    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return;

    *pi = 2;
    free(pi);
    free (pi);       
    /* Defect: pi has already been freed */
}

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

Исправление - удаление дубликатов отмены назначения

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

#include <stdlib.h>

void allocate_and_free(void)
{

    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return;

    *pi = 2;
    free(pi);
    /* Fix: remove second deallocation */
 }
Проблема

Использование ранее освобожденного указателя происходит при доступе к блоку памяти после освобождения блока с помощью 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;
}

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

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

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

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