メインコンテンツ

CERT C: Rule POS50-C

Declare objects shared between POSIX threads with appropriate storage durations

説明

このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされますPolyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください

ルール定義

Declare objects shared between POSIX threads with appropriate storage 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 を宣言して、現在のスレッドが実行を完了したときにスタックから削除されないようにします。

  • スタックではなくヒープ上に割り当てられ、明示的に割り当て解除する必要があるように、変数用のストレージを動的に割り当てます。両方のスレッドが実行を完了してから割り当て解除が実行されることを確認します。

これらの解決策では、非ローカル メモリで変数を作成する必要があります。代わりに、スレッド全体でローカル変数を安全に共有できる OpenMP のスレッド インターフェイスを使用した shared キーワードなどの他の解決策も使用できます。

例 – スレッドをエスケープするローカル変数
#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) { //Noncompliant
    /* 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;
}

この例では、値 parentValmain で始まり、関数 create_parent_thread まで続く親スレッドに対してローカルです。ただし、create_parent_thread の本体では、このローカル変数のアドレスが子スレッド (ルーチン create_child_thread を開始するスレッド) に渡されます。親スレッドは、実行を完了しており、変数 parentVal が子スレッドからアクセスされたときにはスコープから除外されている可能性があります。

修正 – 静的変数を使用

1 つの修正方法として、変数 parentValstatic を宣言して、それらの変数がプログラムの存続期間を通してスタック上に存在するようにします。

#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;
}
修正 – 動的メモリ割り当てを使用

1 つの修正方法として、スレッド全体で共有する変数用のストレージを動的に割り当て、変数が必要なくなったら明示的にストレージを解放します。

#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;
}

チェック情報

グループ: Rule 50.POSIX (POS)

バージョン履歴

R2020a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.