exponenta event banner

CERT C++: MEM51-CPP

Надлежащее выделение динамически выделенных ресурсов

Описание

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

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

Реализация Polyspace

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

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

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

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

Примеры

расширить все

Проблема

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

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

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

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

Риск

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

  • The 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[]. The 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.

Риск

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

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

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