CERT C: Rec. MEM12-C

Рассмотрите использование goto цепи при отъезде функции при ошибке при использовании и высвобождении средств

Описание

Управляйте определением

Рассмотрите использование goto цепи при отъезде функции при ошибке при использовании и выпуске resources.[1]

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

  • Утечка памяти.

  • Утечка ресурсов.

Примеры

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

Проблема

Утечка памяти происходит, когда вы не освобождаете блок от памяти, выделенной через malloc, calloc, realloc, или new. Если память выделяется в функции, дефект не происходит если:

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

  • Функция возвращает указатель, присвоенный malloc, calloc, realloc, или new.

  • Функция хранит указатель в глобальной переменной или в параметре.

Риск

Динамическое выделение памяти функционирует, такие как malloc выделите память на куче. Если вы не выпускаете память после использования, вы уменьшаете объем памяти, доступный для другого выделения. На встраиваемых системах с ограниченной памятью вы можете закончить тем, что исчерпали доступную память кучи даже во время выполнения программы.

Фиксация

Определите осциллограф, где к динамически выделенной памяти получают доступ. Освободите блок памяти в конце этого осциллографа.

Чтобы освободить блок от памяти, используйте free функция на указателе, который использовался во время выделения памяти. Например:

ptr = (int*)malloc(sizeof(int));
...
free(ptr);

Это - хорошая практика, чтобы выделить и освободить память в том же модуле на том же уровне абстракции. Например, в этом примере, func выделяет и освобождает память на том же уровне, но func2 не делает.

void func() {
  ptr = (int*)malloc(sizeof(int));
  {
    ...
  }
  free(ptr);
}

void func2() {
  {
   ptr = (int*)malloc(sizeof(int));
   ...
  }
  free(ptr);
}
См. правило MEM00-C CERT-C.

Пример - динамическая память, не выпущенная перед концом функции
#include<stdlib.h>
#include<stdio.h>

void assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
         printf("Memory allocation failed");
         return;
        }


    *pi = 42;
    /* Defect: pi is not freed */
}

В этом примере, pi динамически выделяется malloc. Функциональный assign_memory не освобождает память, и при этом она не возвращает pi.

Коррекция — свободная память

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

#include<stdlib.h>
#include<stdio.h>

void assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
         printf("Memory allocation failed");
         return;
        }
    *pi = 42;

    /* Fix: Free the pointer pi*/
    free(pi);                   
}
Коррекция — возвращает указатель в динамическое выделение

Другая возможная коррекция должна возвратить указатель pi. Возврат pi позволяет функцию, вызывая assign_memory освободить блок памяти с помощью pi.

#include<stdlib.h>
#include<stdio.h>

int* assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
            printf("Memory allocation failed");
            return(pi);
        }
    *pi = 42;

    /* Fix: Return the pointer pi*/
    return(pi);                   
}
Пример - утечка памяти с новым/удаляют
#define NULL '\0'

void initialize_arr1(void)
{
    int *p_scalar = new int(5);
}

void initialize_arr2(void)
{
    int *p_array = new int[5];
}

В этом примере функции создают две переменные, p_scalar и p_array, использование new ключевое слово. Однако функции заканчиваются, не очищая память для этих указателей. Поскольку функции использовали new чтобы создать эти переменные, необходимо очистить их память путем вызова delete в конце каждой функции.

Коррекция — добавляет, удаляют

Чтобы откорректировать эту ошибку, добавьте delete оператор для каждого new инициализация. Если вы использовали скобки [] чтобы инстанцировать переменной, необходимо вызвать, удаляют со скобками также.

#define NULL '\0'

void initialize_arrs(void)
{
    int *p_scalar = new int(5); 
    int *p_array = new int[5];  

    delete p_scalar;
    p_scalar = NULL;

    delete[] p_array;
    p_scalar = NULL;
}
Проблема

Утечка ресурсов происходит, когда вы открываете поток файла при помощи FILE указатель, но не закрывает его прежде:

  • Конец осциллографа указателя.

  • Присвоение указателя на другой поток.

Риск

Если вы не делаете указателей файла версии явным образом как можно скорее, отказ может произойти из-за исчерпания ресурсов.

Фиксация

Закройте FILE указатель перед концом его осциллографа, или прежде чем вы присвоите указатель на другой поток.

Пример - FILE Указатель, не выпущенный перед концом осциллографа
#include <stdio.h>

void func1( void ) {
    FILE *fp1;
    fp1 = fopen ( "data1.txt", "w" );
    fprintf ( fp1, "*" );

    fp1 = fopen ( "data2.txt", "w" );
    fprintf ( fp1, "!" );
    fclose ( fp1 );
}

В этом примере, указатель файла fp1 указывает на файл data1.txt. Перед fp1 явным образом отделен от потока файла data1.txt, это используется, чтобы получить доступ к другому файлу data2.txt.

Коррекция — выпускает FILE Указатель

Одна возможная коррекция должна явным образом отделить fp1 от потока файла data1.txt.

#include <stdio.h>

void func1( void ) {
    FILE *fp1;
    fp1 = fopen ( "data1.txt", "w" );
    fprintf ( fp1, "*" );
    fclose(fp1);

    fp1 = fopen ( "data2.txt", "w" );                  
    fprintf ( fp1, "!" );
    fclose ( fp1 );
}

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

Группа: Rec. 08. Управление памятью (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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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