メインコンテンツ

CERT C++: EXP52-CPP

Do not rely on side effects in unevaluated operands

説明

ルール定義

未評価のオペランドの二次的影響に依存しないようにします。1

Polyspace 実装

ルール チェッカーは、以下をチェックします。

  • 二次的影響のある論理演算子のオペランド

  • 二次的影響のある sizeofalignof、または decltype オペランド

すべて展開する

問題

この問題は、論理演算子 && または || の右オペランドに二次的影響が含まれている場合に発生します。評価されると、二次的影響のある式はその式内の 1 つ以上の変数を変更します。

チェッカーは、volatile アクセスと関数呼び出しは二次的影響と見なしません。

リスク

評価されると、二次的影響のある式はその式内の 1 つ以上の変数を変更します。たとえば、n++ は二次的影響のある式です。

以下の右側のオペランドについて:

  • 論理 && 演算子の場合は、左側のオペランドが true に評価された場合にのみ評価されます。

  • 論理 || 演算子の場合は、左側のオペランドが false に評価された場合にのみ評価されます。

その他の場合は、右側のオペランドが評価されないため、式の二次的影響が及びません。プログラムが二次的影響に依存している場合は、予期せぬ結果が生じる可能性があります。

修正方法

右側のオペランド内の式を評価するには、別のステートメントで評価を実行します。

たとえば、以下のようにはしません。

if(isOK && n++) {}
次の 2 ステップで演算を実行します。
n++;
if(isOK && n) {}

問題

この問題は、sizeofalignof、または decltype 演算子が二次的影響のある式に対して実行された場合に発生します。評価されると、二次的影響のある式はその式内の 1 つ以上の変数を変更します。

たとえば、n+1 では n が変更されないため、欠陥チェッカーは sizeof(n+1) にフラグを設定しません。n++n を変更することを意図しているため、チェッカーは sizeof(n++) にはフラグを設定します。

リスク

alignof 演算子または decltype 演算子の二次的影響は演算間では持続しません。sizeof 演算子の式は、sizeof(a[n++]) など、可変長配列のサイズを計算するためにそれが必要な場合に限り評価されます。

二次的影響のある式が評価されない場合、二次的影響による変数の変更は発生しません。その変更に依存している場合、予期しない結果になる可能性があります。

修正方法

別のステートメントで二次的影響のある式を評価してから、sizeof_Alignof、または _Generic 演算子でその結果を使用します。

たとえば、以下のようにはしません。

a = sizeof(n++);
次の 2 ステップで演算を実行します。
n++;
a = sizeof(n);

チェッカーは、関数呼び出しを二次的影響のある式と見なします。現在は関数に二次的影響がない場合でも、後の加算に対して二次的影響をもつ可能性があります。関数を sizeof 演算子の外部で呼び出すと、コードの保守が容易になります。たとえば、関数の正しいオーバーロードを選択してから、その戻り値の型を決定するために decltype の関数を呼び出した場合は、チェッカーがそのような呼び出しを例外と見なします。

例 – sizeof のインクリメント演算子
#include <stdio.h>

void func(void) {
    unsigned int a = 1U;
    unsigned int b = (unsigned int)sizeof(++a); //Noncompliant
    printf ("%u, %u\n", a, b);
}

この例では、a を変更することを目的とした ++a に対して sizeof を実行しています。式が評価されないため、変更は発生しません。printf ステートメントにより、a の値が 1 のままであることが示されます。

修正 — sizeof の外部でインクリメントを実行

1 つの修正方法として、最初にインクリメントを実行してから、その結果を sizeof 演算子に渡します。

#include <stdio.h>

void func(void) {
    unsigned int a = 1U;
    ++a;
    unsigned int b = (unsigned int)sizeof (a); 
    printf ("%u, %u\n", a, b);
}

チェック情報

グループ: 02.式 (EXP)

バージョン履歴

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.