CERT.CONC.COND_MULTIPLE_MUTEX

条件変数に対する並行待機操作に複数のミューテックスを使用しない

CERT.CONC.COND_MULTIPLE_MUTEX チェッカーは、異なるミューテックスを使った同一の POSIX 条件変数に対する待機を検出します。スレッドが条件変数で待機している間、その条件変数に対する同時待機はすべて同じミューテックスを使用しなければなりません。

脆弱性とリスク

pthread_cond_wait() および pthread_cond_timedwait() は、スレッドの待機中に指定されたミューテックスのロックを解除し、戻る前にそのミューテックスを再度ロックします。異なるスレッドが異なるミューテックスを使用して同じ条件変数を待機する場合、動作は未定義となり、誤ったミューテックスがロックされた状態でコードが再開される可能性があります。

軽減と防止

各条件変数に正確に 1 つのミューテックスを関連付け、そのミューテックスを条件変数に対するすべての待機操作で使用します。個別のミューテックスが必要な場合は、複数の待機で 1 つの条件変数を共有するのではなく、個別の条件変数を使用してください。

脆弱コード例

コピー
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
static int shared_data = 0;

void *waiter1(void *arg)
{
    pthread_mutex_lock(&mutex1);
    while (shared_data == 0) {
        pthread_cond_wait(&cv, &mutex1);
    }
    pthread_mutex_unlock(&mutex1);
    return NULL;
}

void *waiter2(void *arg)
{
    pthread_mutex_lock(&mutex2);
    while (shared_data == 0) {
        pthread_cond_wait(&cv, &mutex2); /* Noncompliant */
    }
    pthread_mutex_unlock(&mutex2);
    return NULL;
}

この非準拠例では、両方のスレッドが同じ条件変数に対して待機していますが、一方のスレッドは mutex1 を使用し、もう一方は mutex2 を使用しています。条件変数が複数のミューテックスとペアになっているため、2 回目の待機が未定義の動作になります。

修正コード例

コピー
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
static int shared_data = 0;

void *waiter1(void *arg)
{
    pthread_mutex_lock(&mutex1);
    while (shared_data == 0) {
        pthread_cond_wait(&cv, &mutex1);
    }
    pthread_mutex_unlock(&mutex1);
    return NULL;
}

void *waiter2(void *arg)
{
    pthread_mutex_lock(&mutex1);
    while (shared_data == 0) {
        pthread_cond_wait(&cv, &mutex1);
    }
    pthread_mutex_unlock(&mutex1);
    return NULL;
}

準拠ソリューションでは、両方のスレッドが条件変数を持つ同じミューテックスを使用します。個別のミューテックスが必要な場合は、1 つの条件変数を共有するのではなく、個別の条件変数を使用してください。

外部参考資料