CERT C: Rule POS50-C

Объявите объекты, совместно использованные потоками POSIX с соответствующими продолжительностями хранения

Описание

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

Объявите объекты, совместно использованные потоками POSIX с соответствующим устройством хранения данных durations.[1]

Примеры

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

Проблема

Автоматический или локальная переменная потока, сбегающая из потока POSIX®, происходит, когда автоматическая локальная переменная или локальная переменная потока передаются адресом от одного потока POSIX до другого, не гарантируя, что переменная остается в живых через длительность последнего потока.

Риск

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

Например, рассмотрите функцию запуска потока POSIX с этими линиями:

int start_thread(pthread_t *tid) {
   int aVar = 0;
   if(thrd_success != pthread_create(tid, NULL, start_thread_child, &aVar) {
     //...
   }
}

pthread_create функция создает дочерний поток с функцией запуска start_thread_child и передает адрес автоматической переменной aVarк этой функции. Когда этот дочерний поток доступы aVar, родительский поток может завершить выполнение и aVar больше не находится на стеке. Доступ может привести к чтению непредсказуемых значений.

Фиксация

Когда вы передаете переменную от одного потока до другого, убедитесь, что переменное время жизни совпадает или превышает время жизни обоих потоков. Можно достигнуть этой синхронизации одним из этих способов:

  • Объявите переменную static так, чтобы это не выходило из стека, когда текущий поток завершает выполнение.

  • Динамически выделите устройство хранения данных для переменной так, чтобы это было выделено на куче вместо стека и должно было быть явным образом освобождено. Убедитесь, что освобождение происходит после обоих потоков полное выполнение.

Эти решения требуют, чтобы вы создали переменную в нелокальной памяти. Вместо этого можно использовать другие решения, такие как shared ключевое слово с интерфейсом поточной обработки OpenMP, который позволяет вам безопасно совместно использовать локальные переменные через потоки.

Пример – поток выхода локальной переменной
#include <pthread.h>
#include <stdio.h>

void* create_child_thread(void *childVal) {
  int *res = (int *)childVal;
  printf("Result: %d\n", *res);
  return NULL;
}

void create_parent_thread(pthread_t *tid) {
  int parentVal = 1;
  int thrd_success;
  if ((thrd_success = pthread_create(tid, NULL, create_child_thread, &parentVal)) != 0) {
    /* Handle error */
  }
}

int main(void) {
  pthread_t tid;
  int thrd_success;
  create_parent_thread(&tid);

  if ((thrd_success = thrd_join(tid, NULL)) != 0) {
    /* Handle error */
  }
  return 0;
}

В этом примере, значение parentVal локально для родительского потока, который запускается в main и продолжается в функциональный create_parent_thread. Однако в теле create_parent_thread, адрес этой локальной переменной передается дочернему потоку (поток со стандартной программой запуска create_child_thread). Родительский поток может завершить выполнение и переменную parentVal может выйти из осциллографа, когда дочерний поток получает доступ к этой переменной.

Коррекция – использует статические переменные

Одна возможная коррекция должна объявить переменную parentVal как static так, чтобы переменная была на стеке на целое время программы.

#include <pthread.h>
#include <stdio.h>

void* create_child_thread(void *childVal) {
  int *res = (int *)childVal;
  printf("Result: %d\n", *res);
  return NULL;
}

void create_parent_thread(pthread_t *tid) {
  static int parentVal = 1;
  int thrd_success;
  if ((thrd_success = pthread_create(tid, NULL, create_child_thread, &parentVal)) != 0) {
    /* Handle error */
  }
}

int main(void) {
  pthread_t tid;
  int thrd_success;
  create_parent_thread(&tid);

  if ((thrd_success = thrd_join(tid, NULL)) != 0) {
    /* Handle error */
  }
  return 0;
}
Коррекция – использует динамическое выделение памяти

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

#include <pthread.h>
#include <stlib.h>

void* create_child_thread(void *val) {
  int *res = (int *)val;
  printf("Result: %d\n", *res);
  free(res);
  return NULL;
}

void create_parent_thread(pthread_t *tid) {
  int *val;
  int thrd_success;
  
  val = malloc(sizeof(int));
  
  if(!val) {
      *val = 1;
      if ((thrd_success = pthread_create(tid, NULL, create_child_thread, val)) != 0) {
        /* Handle error */
      }
  }
}

int main(void) {
  pthread_t tid;
  int thrd_success;
  create_parent_thread(&tid);

  if ((thrd_success = thrd_join(tid, NULL)) != 0) {
    /* Handle error */
  }
  return 0;
}

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

Группа: правило 50. POSIX (POS)
Введенный в R2020a

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

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