MSC21-C. ループの終了条件には適切な条件式を使う
C言語では、関係演算子として<
、>
、<=
、>=
が用意されている。また、等価演算子としては==
と!=
が用意されている。
for
文やwhile
文でループカウンタを使用する場合、条件式には等価演算子 !=
を用いるよりも、<
などの関係演算子を用いる方が安全である。
違反コード (等価演算子)
以下のコード例では反復処理を5回行うように見えるが、実際にはループは終了しない。
size_t i;
for (i = 1; i != 10; i += 2) {
/* ... */
}
適合コード (関係演算子)
関係演算子 <=
を用いることで、ループは確実に終了する。
size_t i;
for (i = 1; i <= 10; i += 2 ) {
/* ... */
}
違反コード (等価演算子)
また、ループカウンタの初期値と終了値が変数で与えられる場合、ループが確実に終了するよう注意する必要がある。以下の関数では begin < end
が真であると仮定しており、そうでない場合には無限ループになる。
void f(size_t begin, size_t end) {
size_t i;
for (i = begin; i != end; ++i) {
/* ... */
}
}
適合コード (関係演算子)
この場合も、等価演算子ではなく関係演算子を用いることでループが終了することを保証できる。begin >= end
が真の場合、ループの本体は実行されない。
void f(size_t begin, size_t end) {
size_t i;
for (i = begin; i < end; ++i) {
/* ... */
}
}
違反コード (境界条件)
SIZE_MAX
との比較を行う条件式など、ある型で表現できる最大値もしくは最小値との比較を行う場合、必ずしもループを終了しないことがある。
void f(size_t begin, size_t step) {
size_t i;
for (i = begin; i <= SIZE_MAX; i += step) {
/* ... */
}
}
適合コード (境界条件)
以下の適合コードでは、ある型で表現できる最大値とインクリメントする値との差分を、ループカウンタと比較している。
void f(size_t begin, size_t step) {
if (0 < step) {
size_t i;
for (i = begin; i <= SIZE_MAX - step; i += step) {
/* ... */
}
}
}
例外
MSC21-C-EX1: ループの繰り返しごとにループカウンタが+1され、ループ開始時のループカウンタの値がループ終了時の値より小さいもしくは等しいことが事前に分かっているなら、ループの終了条件式に等価演算子を用いてもよい。同様に、繰り返しごとにループカウンタが-1され、ループ開始時のループカウンタの値がループ終了時の値よりも大きいもしくは等しいなら、ループの終了条件式に等価演算子を用いてもよい。
size_t i;
for (i = 1; i != 5; ++i) {
/* ... */
}
リスク評価
等価演算子による判定は、ループの終了に予想以上に時間がかかったり、ループがまったく終了しないというリスクを伴う。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
MSC21-C |
低 |
低 |
低 |
P3 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Astrée |
24.04
|
|
Supported: Astrée reports potential infinite loops. |
CodeSonar |
8.1p0
|
LANG.STRUCT.LOOP.HR |
High risk loop |
Compass/ROSE |
|
|
|
LDRA tool suite |
9.7.1
|
510 S | Partially implemented |
PC-lint Plus |
1.4 |
440, 442, 443, |
Partially supported |
Polyspace Bug Finder |
R2024a |
|
Checks for loop bounded with tainted value (rec. partially covered)
|
PVS-Studio |
7.31 |
V621 |
|
関連ガイドライン
SEI CERT C++ Coding Standard | VOID MSC21-CPP. Use inequality to terminate a loop whose counter changes by more than one |
CERT Oracle Secure Coding Standard for Java | MSC54-J. Avoid inadvertent wrapping of loop counters |
翻訳元
これは以下のページを翻訳したものです。
MSC21-C. Use robust loop termination conditions (revision 63)