メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C: Rec.CON05-C

Do not perform operations that can block while holding a lock

説明

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

ルール定義

ロックの保持中にブロックを行う可能性がある操作を実行しないようにします。1

Polyspace 実装

ルール チェッカーは、"ロック保持中のブロック操作" をチェックします。

すべて展開する

問題

ロック保持中のブロック操作は、タスク (スレッド) で長時間かかる可能性のある操作をロック保持中に実行すると発生します。

チェッカーは、以下の関数の呼び出しを長時間かかる可能性があると見なします。

  • recv などのネットワークにアクセスする関数

  • forkpipesystem などのシステム呼び出し関数

  • getcharscanf などの I/O 操作用の関数

  • fopenremovelstat などのファイル処理関数

  • mkdirrmdir などのディレクトリ操作関数

チェッカーは、ロックの保持および解放を行う特定のプリミティブ型 (たとえば、pthread_mutex_lockpthread_mutex_unlock) を自動的に検出します。自動的に検出されるすべてのプリミティブ型のリストは、Polyspace でのスレッド作成とクリティカル セクションの自動検出を参照してください。

リスク

スレッドでロックの保持中に長時間かかる操作を実行すると、そのロックを使用する他のスレッドはロックが使用可能になるまで待機しなければなりません。その結果、システム パフォーマンスが低下したり、デッドロックが発生する可能性があります。

修正方法

ロックが保持される前か、ロックが解放された後にブロック操作を実行します。

このチェッカーで検出される一部の関数は、時間がかからない可能性のある方法で呼び出すことができます。たとえば、関数 recv は、利用可能なメッセージがない場合に呼び出しが失敗するようになるパラメーター O_NONBLOCK を指定して呼び出せます。このパラメーターを指定して呼び出すと、recv はメッセージが利用可能になるまで待機しません。

例 - ロック保持中の recv でのネットワーク I/O 操作
#include <pthread.h>
#include <sys/socket.h>

pthread_mutexattr_t attr;
pthread_mutex_t mutex;
 
void thread_foo(void *ptr) {
  unsigned int num;
  int result;
  int sock;
 
  /* sock is a connected TCP socket */
 
  if ((result = pthread_mutex_lock(&mutex)) != 0) {
    /* Handle Error */
  }
 
  if ((result = recv(sock, (void *)&num, sizeof(unsigned int), 0)) < 0) { //Noncompliant
    /* Handle Error */
  }
 
  /* ... */
 
  if ((result = pthread_mutex_unlock(&mutex)) != 0) {
    /* Handle Error */
  }
}
 
int main() {
  pthread_t thread;
  int result;
 
  if ((result = pthread_mutexattr_settype(
      &attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
    /* Handle Error */
  }
 
  if ((result = pthread_mutex_init(&mutex, &attr)) != 0) {
    /* Handle Error */
  }
 
  if (pthread_create(&thread, NULL,(void*(*)(void*))& thread_foo, NULL) != 0) {
    /* Handle Error */
  }
 
  /* ... */
 
  pthread_join(thread, NULL);
 
  if ((result = pthread_mutex_destroy(&mutex)) != 0) {
    /* Handle Error */
  }
 
  return 0;
}

この例では、pthread_create を使用して作成した各スレッドにおいて、関数 thread_foopthread_mutex_lock を使用してロックを取得した後に、recv でネットワーク I/O 操作を実行しています。同じロック変数 mutex を使用する他のスレッドは、操作が完了してロックが使用可能になるまで待機しなければなりません。

修正 — ロックの取得前にブロック操作を実行

1 つの修正方法として、ロックの取得前に recv を呼び出します。

#include <pthread.h>
#include <sys/socket.h>

pthread_mutexattr_t attr;
pthread_mutex_t mutex;
 
void thread_foo(void *ptr) {
  unsigned int num;
  int result;
  int sock;
 
  /* sock is a connected TCP socket */
  if ((result = recv(sock, (void *)&num, sizeof(unsigned int), 0)) < 0) {
    /* Handle Error */
  }
  
  if ((result = pthread_mutex_lock(&mutex)) != 0) {
    /* Handle Error */
  }
 
    /* ... */
 
  if ((result = pthread_mutex_unlock(&mutex)) != 0) {
    /* Handle Error */
  }
}
 
int main() {
  pthread_t thread;
  int result;
 
  if ((result = pthread_mutexattr_settype(
      &attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
    /* Handle Error */
  }
 
  if ((result = pthread_mutex_init(&mutex, &attr)) != 0) {
    /* Handle Error */
  }
 
  if (pthread_create(&thread, NULL,(void*(*)(void*))& thread_foo, NULL) != 0) {
    /* Handle Error */
  }
 
  /* ... */
 
  pthread_join(thread, NULL);
 
  if ((result = pthread_mutex_destroy(&mutex)) != 0) {
    /* Handle Error */
  }
 
  return 0;
}

チェック情報

グループ: Rec.14.同時実行 (CON)

バージョン履歴

R2019a で導入


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.