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

Пример - освобождение ранее освобожденной ошибки указателя

#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 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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