メインコンテンツ

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

誤って起動する可能性のある関数はループでラップされません

誤りの可能性がある起動後のループによる起動条件のチェック

説明

この欠陥は、以下の待機条件関数が、ループの外側から呼び出された場合に発生します。

  • C 関数:

    • cnd_wait()

    • cnd_timedwait()

  • POSIX 関数:

    • pthread_cond_wait()

    • pthread_cond_timedwait()

  • C++ の std::condition_variable および std::condition_variable_any クラス メンバー関数:

    • wait()

    • wait_until()

    • wait_for()

待機条件関数は、指定された条件が満たされた場合に呼び出し元スレッドの実行を一時停止します。そのスレッドは、別のスレッドから cnd_broadcast() または同等の関数を使用して通知されるとすぐに起動および再開されます。起動通知は誤りであったり悪意のものであったりする場合があります。

リスク

スレッドが誤った起動通知を受け取り、そのときに待機条件関数の条件がチェックされていない場合、スレッドが途中で起動する可能性があります。その起動は、予期しない制御フロー、他のスレッドの無期限のブロック、またはサービス拒否の原因になるおそれがあります。

修正方法

誤って起動する可能性のある待機条件関数をループ内にラップします。誤りの可能性がある起動通知後に、ループで起動条件をチェックします。

すべて展開する

#include <stdio.h>
#include <stddef.h>
#include <threads.h>

#define THRESHOLD 100

static mtx_t lock;
static cnd_t cond;

void func(int input)
{
    if (thrd_success != mtx_lock(&lock)) {
        /* Handle error */
    }
    /* test condition to pause thread */
    if (input > THRESHOLD) {
        if (thrd_success != cnd_wait(&cond, &lock)) {
            /* Handle error */
        }
    }
    /* Proceed if condition to pause does not hold */


    if (thrd_success != mtx_unlock(&lock)) {
        /* Handle error */
    }
}

この例では、inputTHRESHOLD よりも大きい場合、スレッドは cnd_wait() を使用して実行を一時停止します。一時停止したスレッドは、すべてのスレッドに通知を行う cnd_broadcast() が別のスレッドで使用されると再開される可能性があります。この通知により、一時停止条件が true から変わっていない場合でもスレッドが起動することになります。

修正 — cnd_wait()while ループ内にラップ

1 つの修正方法として、cnd_wait()while 内にラップします。誤りの可能性がある起動通知をスレッドで受け取った後に、ループで一時停止条件をチェックします。

#include <stdio.h>
#include <stddef.h>
#include <threads.h>

#define THRESHOLD 100

static mtx_t lock;
static cnd_t cond;

void func(int input)
{
    if (thrd_success != mtx_lock(&lock)) {
        /* Handle error */
    }
    /* test condition to pause thread */
    while (input > THRESHOLD) {
        if (thrd_success != cnd_wait(&cond, &lock)) {
            /* Handle error */
        }
    }
    /* Proceed if condition to pause does not hold */


    if (thrd_success != mtx_unlock(&lock)) {
        /* Handle error */
    }
}
 

結果情報

グループ: 同時実行
言語: C | C++
既定値: オフ
コマンド ライン構文: SPURIOUS_WAKEUP_NOT_WRAPPED_IN_LOOP
影響度: Low

バージョン履歴

R2018b で導入