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
節に入った時に p
が NULL
である場合のみである。そのため、free()
が呼ばれるときにポインタは malloc()
が割り当てていないローカルデータを参照しているかもしれない。(「MEM34-C. 動的に割り当てられたメモリのみを解放する」を参照。)これは、malloc()
が実際に呼ばれたかどうかはっきりしないというのも原因である。
適合コード
以下の適合コードでは、2つ目のポインタである q
を使用して malloc()
が呼ばれたかどうかを表している。malloc()
が呼び出されていない場合、q
は NULL
のままである。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 |
実装済み |
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)