CERT C: Rec. MEM12-C

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

Описание

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

Рассмотрите использование цепи goto при оставлении функции от ошибки при использовании и освобождении ресурсов.[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);
}
См. Раздел «Правила CERT-C MEM00-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 функция. The 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);                   
}
Проблема

Утечка ресурсов происходит, когда вы открываете поток файлов при помощи 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 );
}

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

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

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

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