メインコンテンツ

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

CERT C: Rule POS47-C

非同期でキャンセル可能なスレッドを使用しない

説明

ルール定義

非同期でキャンセル可能なスレッドを使用しないようにします。1

Polyspace 実装

ルール チェッカーは、"非同期にキャンセル可能なスレッド" をチェックします。

すべて展開する

問題

この問題は、pthread_setcanceltype を引数 PTHREAD_CANCEL_ASYNCHRONOUS と一緒に使用して、呼び出し元スレッドのキャンセル可能性タイプを非同期 (または即時) に設定したときに発生します。非同期でキャンセル可能なスレッドは、いつでも、通常は、キャンセル要求の受信直後にキャンセルできます。

リスク

呼び出し元スレッドが、リソース リーク、デッドロック、データ レース、データ破損、または予測できない動作につながる安全ではない状態でキャンセルされる可能性があります。

修正方法

引数 PTHREAD_CANCEL_ASYNCHRONOUS を指定した pthread_setcanceltype の呼び出しを削除して、代わりに、既定のキャンセル可能性タイプ PTHREAD_CANCEL_DEFERRED を使用します。既定のキャンセル可能性タイプを使用して、スレッドは、キャンセル ポイントである関数を呼び出すまでキャンセル要求を延期します。

例 - 非同期に設定されたスレッドのキャンセル可能性タイプ
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

static int fatal_error(void)
{
    exit(1);
}


volatile int a = 5;
volatile int b = 10;

pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

void* swap_values_thread(void* dummy)
{
    int i;
    int c;
    int result;
    if ((result =
             pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i)) != 0) { //Noncompliant
        /* handle error */
        fatal_error();
    }
    while (1) {
        if ((result = pthread_mutex_lock(&global_lock)) != 0) {
            /* handle error */
            fatal_error();
        }
        c = b;
        b = a;
        a = c;
        if ((result = pthread_mutex_unlock(&global_lock)) != 0) {
            /* handle error */
            fatal_error();
        }
    }
    return NULL;
}

int main(void)
{
    int result;
    pthread_t worker;

    if ((result = pthread_create(&worker, NULL, swap_values_thread, NULL)) != 0) {
        /* handle error */
        fatal_error();
    }

    /* Additional code */

    if ((result = pthread_cancel(worker)) != 0) {
        /* handle error */
        fatal_error();
    }


    if ((result = pthread_join(worker, 0)) != 0) {
        /* handle error */
        fatal_error();
    }

    if ((result = pthread_mutex_lock(&global_lock)) != 0) {
        /* handle error */
        fatal_error();
    }
    printf("a: %i | b: %i", a, b);
    if ((result = pthread_mutex_unlock(&global_lock)) != 0) {
        /* handle error */
        fatal_error();
    }

    return 0;
}

この例では、worker スレッドのキャンセル可能性タイプが非同期に設定されます。ミューテックス global_lock によって、worker スレッドと main スレッドがアクセス変数の ab に同時にアクセスしないようになります。ただし、worker スレッドが global_lock の保持中にキャンセルされる可能性があり、その場合は、main スレッドが global_lock を取得することはなく、デッドロックが発生します。

修正 — 既定のキャンセル可能性タイプを使用

1 つの修正方法として、pthread_setcanceltype に対する呼び出しを削除します。既定で、新しいスレッドのキャンセル可能性タイプは PTHREAD_CANCEL_DEFERRED に設定されます。worker スレッドは、キャンセル ポイントである関数を呼び出すまでキャンセル要求を延期します。

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

static int fatal_error(void)
{
    exit(1);
}


volatile int a = 5;
volatile int b = 10;

pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

void* swap_values_thread(void* dummy)
{
    int i;
    int c;
    int result;
    while (1) {
        if ((result = pthread_mutex_lock(&global_lock)) != 0) {
            /* handle error */
            fatal_error();
        }
        c = b;
        b = a;
        a = c;
        if ((result = pthread_mutex_unlock(&global_lock)) != 0) {
            /* handle error */
            fatal_error();
        }
    }
    return NULL;
}

int main(void)
{
    int result;
    pthread_t worker;

    if ((result = pthread_create(&worker, NULL, swap_values_thread, NULL)) != 0) {
        /* handle error */
        fatal_error();
    }

    /* Additional code */

    if ((result = pthread_cancel(worker)) != 0) {
        /* handle error */
        fatal_error();
    }


    if ((result = pthread_join(worker, 0)) != 0) {
        /* handle error */
        fatal_error();
    }

    if ((result = pthread_mutex_lock(&global_lock)) != 0) {
        /* handle error */
        fatal_error();
    }
    printf("a: %i | b: %i", a, b);
    if ((result = pthread_mutex_unlock(&global_lock)) != 0) {
        /* handle error */
        fatal_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.