メインコンテンツ

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

CERT C: Rule CON40-C

Do not refer to an atomic variable twice in an expression

説明

ルール定義

式の中でアトミック変数を 2 回参照しないようにします。1

Polyspace 実装

ルール チェッカーは以下の問題をチェックします。

  • 式の中でアトミック変数へのアクセスが 2 回行われています

  • アトミックな読み込みと保存のシーケンスがアトミックではありません

すべて展開する

問題

式の中でアトミック変数へのアクセスが 2 回行われていますは、C のアトミック型または C++ の std::atomic クラスの変数が 1 つの式の中で 2 回登場する場合に発生します。これには次のようなものがあります。

  • 変数に対する 2 回のアトミックな読み取り操作。

  • 変数に対するアトミックな読み取り操作と別個のアトミックな書き込み操作。

C 標準では、スレッドセーフになっていて、データ レース状態を引き起こさない、アトミック変数に対する特定の操作が定義されています。個別の操作とは異なり、1 つの式における同じアトミック変数に対する 1 組の操作はスレッドセーフではありません。

リスク

スレッドは、1 組のアトミック操作の間にアトミック変数を変更することができ、その結果、データ レース状態になる可能性があります。

修正方法

同じ式の中でアトミック変数を 2 回参照しないようにします。

例 - 1 つの式内でアトミック変数を 2 回参照

この例では、グローバル変数 ncompute_sum() の return ステートメント内で 2 回参照されています。n の値は、2 つの別個の読み取り操作の間に変わる可能性があります。compute_sum() は誤った値を返すおそれがあります。

この違反を確認するには、このコードに対して Polyspace® Bug Finder™ を実行し、コンパイラとして gnu4.9 を指定します。コンパイラ (-compiler) を参照してください。

#include <stdatomic.h>

atomic_int n = ATOMIC_VAR_INIT(0);

int compute_sum(void)
{
    return n * (n + 1) / 2; //Noncompliant
}
修正 — 変数を関数の引数として渡す

1 つの修正方法として、変数を関数の引数 n として渡します。変数はメモリにコピーされ、そのコピーに対する読み取り操作により compute_sum() で正しい結果が返されることが保証されます。atomic_int 型の代わりに int 型の変数を渡す場合でも、この修正は有効です。

#include <stdatomic.h>

int compute_sum(atomic_int n)
{
    return n * (n + 1) / 2;
}
問題

アトミックな読み込みと保存のシーケンスがアトミックではありませんは、以下の関数を使用してアトミック変数を読み込んだ後に、その変数を格納すると発生します。

  • C 関数:

    • atomic_load()

    • atomic_load_explicit()

    • atomic_store()

    • atomic_store_explicit()

  • C++ 関数:

    • std::atomic_load()

    • std::atomic_load_explicit()

    • std::atomic_store()

    • std::atomic_store_explicit()

    • std::atomic::load()

    • std::atomic::store()

スレッドは、変数に対するアトミックな読み込み操作やアトミックな格納操作に割り込むことはできませんが、格納に割り込んでから、シーケンスを読み込むことはできます。

リスク

スレッドは読み込み操作と格納操作の間に変数を変更することができ、その結果、データ レース状態になります。

修正方法

変数をアトミックに読み取って、変更し、格納するには、+= などの複合代入演算子か、atomic_compare_exchange() または atomic_fetch_* のファミリ関数を使用します。

例 - アトミック変数の読み込み後の格納

この例では、atomic_bool 型の変数 flag が関数 toggle_flag() 内で 2 回参照されています。この関数は変数を読み込み、その値を否定して、新しい値を元の変数に格納します。2 つのスレッドで toggle_flag() を呼び出す場合、2 つ目のスレッドは 1 つ目のスレッドの読み込み操作と格納操作の間に flag にアクセスできます。最終的に flag が不適切な状態になる可能性があります。

この違反を確認するには、このコードに対して Polyspace Bug Finder を実行し、コンパイラとして gnu4.9 を指定します。コンパイラ (-compiler) を参照してください。

#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void init_flag(void)
{
    atomic_init(&flag, false);
}

void toggle_flag(void)
{
    bool temp_flag = atomic_load(&flag);
    temp_flag = !temp_flag;
    atomic_store(&flag, temp_flag); //Noncompliant
}

bool get_flag(void)
{
    return atomic_load(&flag);
}
修正 — 複合代入を使用して変数を変更

1 つの修正方法として、複合代入演算子を使用して flag の値を切り替えます。C 標準では、^= を使用して操作をアトミックとして定義します。

#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void toggle_flag(void)
{
    flag ^= 1;
}

bool get_flag(void)
{
    return flag;
}

チェック情報

グループ: Rule 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.