JPCERT コーディネーションセンター

EXP02-C. 論理 AND 演算子および論理 OR 演算子のショートサーキット動作について注意する

論理AND演算子(&&) および論理OR演算子(||)は「ショートサーキット」動作をする。つまり、第一オペランドを評価するだけで結果が分かる場合は第二オペランドを評価しない。

第二引数に副作用が存在する場合には注意すべきである。なぜなら、その副作用が実際に起こるかどうかが分からないからである。

以下のコードでは、i >= 0 の場合に i の値がインクリメントされる。

enum { max = 15 };
int i = /* ユーザが与えた初期値 */;

if ( (i >= 0) && ( (i++) <= max) ) {
  /* 何らかの処理を行うコード */
}

動作は明確に定義されているが、一見して i がインクリメントされるのかされないのかが分かりにくい。

違反コード

以下のコードでは、論理OR演算子の第二オペランドが関数呼び出しを行っており、これが副作用を引き起こす。

char *p = /* 初期化する。NULL が入るかもしれないし、NULL でないかもしれない。 */

if (p || (p = (char *) malloc(BUF_SIZE)) ) {
  /* p を使った処理 */
  free(p);
  p = NULL;
}
else {
  /* malloc() エラーの処理 */
  return;
}

malloc() が呼び出されるのは、if 節に入った時に pNULL である場合のみである。そのため、free() が呼ばれるときにポインタは malloc() が割り当てていないローカルデータを参照しているかもしれない。(「MEM34-C. 動的に割り当てられたメモリのみを解放する」を参照。)これは、malloc() が実際に呼ばれたかどうかはっきりしないというのも原因である。

適合コード

以下の適合コードでは、2つ目のポインタである q を使用して malloc() が呼ばれたかどうかを表している。malloc() が呼び出されていない場合、qNULL のままである。free()NULL を渡しても安全で何もしないことが保証されている。

char *p;
char *q = NULL;
if (p == NULL) {
  q = (char *) malloc(BUF_SIZE);
  p = q;
}
if (p == NULL) {
  /* malloc() エラーの処理 */
  return;
}

/* p を使った処理 */
free(q);
q = NULL;
リスク評価

論理 OR 演算子と論理 AND 演算子のショートサーキット動作について理解していないと、プログラムの意図せぬ動作を引き起こす恐れがある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

EXP02-C

P2

L3

自動検出

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

副作用を持つ式をレポートすることで、このレコメンデーションの違反の可能性を検出できるかもしれない。オペレータ && および || の右辺に出現する関数呼び出しなどがこれに含まれる。

LDRA tool suite

V. 8.5.4

35 D
1 Q
133 S
406 S
408 S

実装済み

PRQA QA-C 8.1 3415 実装済み
関連するガイドライン
CERT C++ Secure Coding Standard EXP02-CPP. Be aware of the short-circuit behavior of the logical AND and OR operators
MITRE CWE CWE-768, Incorrect short circuit evaluation
翻訳元

これは以下のページを翻訳したものです。

EXP02-C. Be aware of the short-circuit behavior of the logical AND and OR operators (revision 64)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter