exponenta event banner

CERT C++: MEM51-CPP

Правильно освобождать динамически выделенные ресурсы

Описание

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

Правильно перераспределить динамически выделенные ресурсы [1 ].

Внедрение Polyspace

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

  • Недопустимое удаление указателя.

  • Недопустимое отсутствие указателя.

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

Примеры

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

Проблема

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

  • Вы освобождаете блок памяти с помощью delete но память ранее не выделялась с помощью new оператор.

  • Вы освобождаете блок памяти с помощью delete оператор, использующий однообъектную нотацию, но память ранее была выделена как массив с new оператор.

Этот дефект относится только к исходным файлам C++.

Риск

Риск зависит от причины проблемы:

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

  • Если используется однообъектная нотация для delete на указателе, который ранее был выделен с помощью нотации массива для new, поведение не определено.

Проблема также может выделить другие ошибки кодирования. Например, вы, возможно, хотели использовать delete оператор или предыдущий new на другом указателе.

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

Исправление зависит от причины проблемы:

  • В большинстве случаев проблему можно устранить, удалив delete заявление. Если указатель не выделен памяти из кучи с new оператор, не требуется отпускать указатель с помощью delete. При необходимости можно просто повторно использовать указатель или разрешить уничтожение объекта в конце его области.

  • В случае несовпадения обозначений для new и delete, исправьте несоответствие. Например, чтобы выделить и освободить один объект, используйте следующую нотацию:

    classType* ptr = new classType;
    delete ptr;

    Чтобы выделить и освободить объекты массива, используйте следующую нотацию:

    classType* p2 = new classType[10];
    delete[] p2;

Если проблема подчеркивает ошибку кодирования, такую как использование delete или new не на том указателе, исправьте ошибку.

Пример - Удаление статической памяти
void assign_ones(void)
{
    int ptr[10];

    for(int i=0;i<10;i++)
        *(ptr+i)=1;  

    delete[] ptr;   
}

Указатель ptr освобождается с помощью delete оператор. Однако ptr указывает на папку памяти, которая не была динамически выделена.

Исправление: Удаление удаления указателя

Если количество элементов массива ptr известен во время компиляции, одной из возможных корректировок является удаление отмены выделения указателя ptr.

void assign_ones(void) 
{
    int ptr[10];

    for(int i=0;i<10;i++)
        *(ptr+i)=1;  
}
Исправление - Добавление назначения указателя

Если количество элементов массива неизвестно во время компиляции, одной из возможных корректировок является динамическое выделение памяти массиву. ptr с использованием new оператор.

void assign_ones(int num) 
{
    int *ptr = new int[num]; 

    for(int i=0; i < num; i++)
        *(ptr+i) = 1;

    delete[] ptr;
   }
Пример - Несоответствие new и delete
int main (void)
{
    int *p_scale = new int[5];

    //more code using scal

    delete p_scale;
}

В этом примере: p_scale инициализирован массивом размера 5 с использованием new int[5]. Однако p_scale удаляется с помощью delete вместо delete[]. new-delete пара не совпадает. Не использовать delete без скобок при удалении массивов.

Коррекция - совпадение delete кому new

Одним из возможных исправлений является добавление скобок для delete соответствует new [] объявление.

int main (void)
{
    int *p_scale = new int[5];

    //more code using p_scale

    delete[] p_scale;
}
Коррекция - совпадение new кому delete

Другой возможной поправкой является изменение объявления p_scale. Если вы хотите инициализировать p_scale как 5 вместо массива размера 5, необходимо использовать другой синтаксис. Для этого исправления измените квадратные скобки в инициализации на круглые скобки. Оставить delete заявление как есть.

int main (void)
{
    int *p_scale = new int(5);

    //more code using p_scale

    delete p_scale;
}
Проблема

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

Риск

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

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

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

В большинстве случаев проблему можно устранить, удалив free заявление. Если указатель не выделен памяти из кучи с malloc или calloc, не нужно освобождать указатель. При необходимости можно просто повторно использовать указатель.

Если проблема подчеркивает ошибку кодирования, такую как использование free или malloc не на том указателе, исправьте ошибку.

Если проблема возникает из-за использования free для освобождения памяти, выделенной с помощью new оператор, замените free функции с помощью delete оператор.

Пример - недопустимая ошибка без указателя
#include <stdlib.h>

void Assign_Ones(void) 
{
  int p[10];
  for(int i=0;i<10;i++)
     *(p+i)=1; 
 
  free(p);   
  /* Defect: p does not point to dynamically allocated memory */
}

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

Исправление - Удаление удаления указателя

Если количество элементов массива p известен во время компиляции, одной из возможных корректировок является удаление отмены выделения указателя p.

#include <stdlib.h>

void Assign_Ones(void)
 {
  int p[10];
  for(int i=0;i<10;i++)
     *(p+i)=1;   
  /* Fix: Remove deallocation of p */
 }
Исправление - Введение назначения указателя

Если количество элементов массива p неизвестно во время компиляции, одной из возможных корректировок является динамическое выделение памяти массиву p.

#include <stdlib.h>

void Assign_Ones(int num) 
{
  int *p;
  /* Fix: Allocate memory dynamically to p */
  p=(int*) calloc(10,sizeof(int)); 
  for(int i=0;i<10;i++)
     *(p+i)=1; 
  free(p); 
}
Проблема

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

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

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

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

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