メインコンテンツ

CWE Rule 480

Use of Incorrect Operator

R2023a 以降

説明

ルールの説明

The programmer accidentally uses the wrong operator, which changes the application logic in security-relevant ways.

Polyspace 実装

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

  • = (代入) 演算子の無効な使用

  • == (等号) 演算子の無効な使用

  • ビット演算子と boolean 形式のオペランドの使用

すべて展開する

問題

この問題は、ifwhile などの条件付きステートメントの述部内で代入が行われた場合に発生します。

C および C++ では、単一の等号は比較ではなく代入を表します。条件付きステートメントで単一の等号を使用している場合は、誤入力やミスである可能性があります。

リスク
  • 条件付きステートメントによる間違った値のテスト - 単一等号の演算は右辺のオペランドの値を左辺のオペランドに代入します。この代入は条件付きの述部内で行われるため、プログラムでは左辺のオペランドの新しい値が非ゼロかつ非 NULL であることがチェックされます。

  • 保守およびコードの可読性の問題 - 代入を意図した場合でも、コードを読む際、または更新する際に、代入ではなく、誤って等値比較と解釈する可能性があります。

修正方法
例 — if 条件内部の単一等号
#include <stdio.h>

void bad_equals_ex(int alpha, int beta)
{
    if(alpha = beta)  //Noncompliant
    {
        printf("Equal\n");
    }
}

if ステートメントの述部内で代入演算子が使用されているため、この等号に欠陥としてのフラグが付けられます。述部は、値 betaalpha に代入し、次に alpha が true か false かを暗黙的にテストします。

修正 — 式を比較に変更

1 つの修正方法として、等号を追加することができます。この修正により、代入が比較に変わります。if 条件は alphabeta が等しいかどうかを比較します。

#include <stdio.h>

void equality_test(int alpha, int beta)
{
    if(alpha == beta)
    {
        printf("Equal\n");
    }
}
修正 - if 条件内での代入と比較

述部内で代入を行わなければならない場合、考えられる 1 つの修正方法として、明示的な比較を追加します。この修正により、beta の値が alpha に代入され、次に alpha が非ゼロであるかどうかが明示的にチェックされます。コードが明確になります。

#include <stdio.h>

int assignment_not_zero(int alpha, int beta)
{
    if((alpha = beta) != 0)
    {
        return alpha;
    }
    else
    {
        return 0;
    }
}
修正 — if ステートメント外部に代入を移動

制御ステートメント外部で代入を行うことができる場合、考えられる 1 つの修正方法として、代入と比較を分離します。この修正により、if の前に beta の値が alpha に代入されます。if 条件内では alpha のみを指定し、alpha が非ゼロかつ非 NULL であることをテストします。

#include <stdio.h>

void assign_and_print(int alpha, int beta)
{
    alpha = beta;
    if(alpha)
    {
        printf("%d", alpha);
    }
}
問題

この問題は、単純なステートメントで代入演算子ではなく等号演算子が使用された場合に発生します。

リスク

= 演算子ではなく == 演算子を使用すると、気付かないうちに間違った結果が生じる可能性があります。変数に値を代入することを意図していた場合、代入は行われません。変数は以前の値を保持するか、以前に初期化されていない場合、未初期化のままになります。

修正方法

== (等号) 演算子ではなく、= (代入) 演算子を使用します。

次のような代入演算子と等号演算子の連鎖に対してチェックが表示されます。

compFlag = val1 == val2;
コードの可読性を高めるために、等価性チェックをかっこに入れます。
compFlag = (val1 == val2);

== 演算子の使用を意図している場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 — for ループ内の等価性評価
void populate_array(void)
{
    int i = 0;
    int j = 0;
    int array[4];

    for (j == 5; j < 9; j++)  //Noncompliant
    {
        array[i] = j;
        i++;
    }
}

for ループ内で、ステートメント j == 5j を 5 に設定するのではなく、j が 5 と等しいかどうかをテストします。j の値が 5 ではなく 0 から開始されるため、for ループは 0 から 8 まで反復します。等号演算子の無効な使用により、次の行で範囲外の配列アクセスが副次的に発生します。

修正 — 代入演算子に変更

1 つの修正方法として、== 演算子を 1 つの等号 (=) に変更することができます。== 記号を変更することで想定どおりの回数 for ループが反復されるため、両方の欠陥が解決します。

void populate_array(void)
{
    int i = 0;
    int j = 0;
    int array[4];

    for (j = 5; j < 9; j++) {
        array[i] = j;
        i++;
    }
}
問題

この問題は、次のようなビット演算子を使用したときに発生します。

  • ビット単位 AND (&&=)

  • ビット単位 OR (||=)

  • ビット単位 XOR (^^=)

  • ビット単位 NOT (~)

  • boolean 型の変数

  • 関係式または等式の出力

boolean 算術式とシフト演算で boolean 型の変数を配列インデックスとして使用してもこの欠陥は発生しません。

リスク

bool 型の変数や関係演算子の出力などの boolean 形式のオペランドは、通常、論理式で使用されます。boolean 変数や関係演算子を含む式でビット演算子を使用すると、論理エラーが発生する可能性があります。ビット演算子と論理演算子は似ているため、誤って論理演算子の代わりにビット演算子を使用することがあります。このような論理エラーは、コンパイル エラーにならないため、見つけにくいコード内のバグにつながる可能性があります。

修正方法

boolean 変数や関係演算子を含む式で論理演算子を使用します。このような式でビット演算子を使用する意図を示すには、小かっこを使用します。

例 — ビット演算子を使用したことで発生する可能性のあるバグ
class User{
	//...
	int uid;
	int euid;
public:
	int getuid();
	int geteuid();
};
void Noncompliant ()
{
	User nU;
	if (nU.getuid () & nU.geteuid () == 0) {   //Noncompliant
		//...
	}else{
		//...
	}
}

この例では、if-else ブロックが条件付きで実行されます。条件ステートメントでは、論理 AND (&&) の代わりに、ビット単位 AND (&) が使用されていますが、間違っている可能性があります。関数 nU.geteuid() が 0 に評価され、nU.getuid() が 2 に評価される場合を考えてみます。このケースでは、& を使用すると、2&1false に評価されるため、コードの else ブロックが実行されます。逆に、&& を使用すると、2&&1true に評価されるため、コードの if ブロックが実行されます。&& の代わりに & を使用すると、見つけにくいコード内の論理エラーやバグにつながる可能性があります。Polyspace® は、関係演算子も使用されるこの種の式でのビット演算子の使用にフラグを設定します。

修正 — 論理演算子と boolean 形式のオペランドの使用

1 つの考えられる修正は、関係演算子や boolean 変数を含む式では論理演算子を使用することです。

class User{
	//...
	int uid;
	int euid;
public:
	int getuid();
	int geteuid();
};
void Noncompliant ()
{
	User nU;
	if (nU.getuid () && nU.geteuid () == 0) {   //Compliant
		//...
	}else{
		//...
	}
}

チェック情報

カテゴリ: Behavioral Problems

バージョン履歴

R2023a で導入