CERT C: правило CON30-C

Очистите специфичное для потока устройство хранения данных

Описание

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

Очистите специфичное для потока устройство хранения данных. [1]

Примеры

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

Описание

Специфичная для потока утечка памяти происходит, когда вы не освобождаете специфичную для потока динамически выделенную память перед концом потока.

Чтобы создать специфичное для потока устройство хранения данных, вы обычно выполняете эти шаги:

  1. Вы создаете ключ для специфичного для потока устройства хранения данных.

  2. Вы создаете потоки.

  3. В каждом потоке вы выделяете устройство хранения данных динамически и затем сопоставляете ключ с этим устройством хранения данных.

    После ассоциации можно считать хранимые данные позже с помощью ключа.

  4. Перед концом потока вы освобождаете специфичную для потока память с помощью ключа.

Средство проверки отмечает пути к выполнению в потоке, где последний шаг отсутствует.

Средство проверки работает над этими семействами функций:

  • tss_get и tss_set (C11)

  • pthread_getspecific и pthread_setspecific (POSIX)

Риск

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

Фиксация

Свободная динамически выделенная память перед концом потока.

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

Также, когда вы создаете ключ, можно сопоставить функцию деструктора с ключом. Функция деструктора вызвана со значением ключа в качестве аргумента в конце потока. В теле функции деструктора можно освободить любую память, сопоставленную с ключом. Если вы используете этот метод, Средство поиска Ошибки все еще отмечает дефект. Проигнорируйте этот дефект с соответствующими комментариями. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.

Пример - память, не освобожденная в конце потока

#include <threads.h>
#include <stdlib.h>
 
/* Global key to the thread-specific storage */
tss_t key;
enum { MAX_THREADS = 3 };
 

int add_data(void) {
  int *data = (int *)malloc(2 * sizeof(int));
  if (data == NULL) {
    return -1;  /* Report error  */
  }
  data[0] = 0;
  data[1] = 1;
 
  if (thrd_success != tss_set(key, (void *)data)) {
    /* Handle error */
  }
  return 0;
}
 
void print_data(void) {
  /* Get this thread's global data from key */
  int *data = tss_get(key);
 
  if (data != NULL) {
    /* Print data */
  }
}
 
int func(void *dummy) {
  if (add_data() != 0) {
    return -1;  /* Report error */
  }
  print_data();
  return 0;
}
 
int main(void) {
  thrd_t thread_id[MAX_THREADS];
 
  /* Create the key before creating the threads */
  if (thrd_success != tss_create(&key, NULL)) {
    /* Handle error */
  }
 
  /* Create threads that would store specific storage */
  for (size_t i = 0; i < MAX_THREADS; i++) {
    if (thrd_success != thrd_create(&thread_id[i], func, NULL)) {
      /* Handle error */
    }
  }
 
  for (size_t i = 0; i < MAX_THREADS; i++) {
    if (thrd_success != thrd_join(thread_id[i], NULL)) {
      /* Handle error */
    }
  }
 
  tss_delete(key);
  return 0;
}

В этом примере функции запуска каждого потока func вызывает две функции:

  • add_data: Эта функция выделяет устройство хранения данных динамически и сопоставляет устройство хранения данных с ключом с помощью функции tss_set.

  • print_data: Эта функция читает хранимые данные с помощью функции tss_get.

В точках, куда func возвращается, не было освобождено динамически выделенное устройство хранения данных.

Исправление — свободная динамически выделенная память явным образом

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

В этой исправленной версии дефект все еще появляется на операторе return в разделе обработки ошибок func. Дефект не может произойти на практике, потому что раздел обработки ошибок вводится, только если динамическое выделение памяти перестало работать. Проигнорируйте этот остающийся дефект с соответствующими комментариями. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.

#include <threads.h>
#include <stdlib.h>
 
/* Global key to the thread-specific storage */
tss_t key;
enum { MAX_THREADS = 3 };
 

int add_data(void) {
  int *data = (int *)malloc(2 * sizeof(int));
  if (data == NULL) {
    return -1;  /* Report error  */
  }
  data[0] = 0;
  data[1] = 1;
 
  if (thrd_success != tss_set(key, (void *)data)) {
    /* Handle error */
  }
  return 0;
}
 
void print_data(void) {
  /* Get this thread's global data from key */
  int *data = tss_get(key);
 
  if (data != NULL) {
    /* Print data */
  }
}
 
int func(void *dummy) {
  if (add_data() != 0) {
    return -1;  /* Report error */
  }
  print_data();
  free(tss_get(key));
  return 0;
}
 
int main(void) {
  thrd_t thread_id[MAX_THREADS];
 
  /* Create the key before creating the threads */
  if (thrd_success != tss_create(&key, NULL)) {
    /* Handle error */
  }
 
  /* Create threads that would store specific storage */
  for (size_t i = 0; i < MAX_THREADS; i++) {
    if (thrd_success != thrd_create(&thread_id[i], func, NULL)) {
      /* Handle error */
    }
  }
 
  for (size_t i = 0; i < MAX_THREADS; i++) {
    if (thrd_success != thrd_join(thread_id[i], NULL)) {
      /* Handle error */
    }
  }
 
  tss_delete(key);
  return 0;
}

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

Группа: правило 14. Параллелизм (CON)

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

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