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

EXP19-C. if、for、while 文の本体は波括弧で囲む

EXP19-C. if、for、while 文の本体は波括弧で囲む

ifforwhile 文に対しては、本体に単一の文しか含まれていない場合でも、必ず開始と終了の波括弧を使用すること。

ifwhilefor 文をマクロの中で使用する場合、マクロ定義の最後をセミコロンで終端すべきではない(「PRE11-C. マクロ定義をセミコロンで終端しない」を参照)。

波括弧を使用することでコードの一貫性が保たれ、読みやすさも向上する。より重要なことは、文が 1 つしかない本体に新たに文を追加するときに、字下げがその構造に対する強固な(しかし誤解を招きやすい)目安となるため、波括弧を付けるのを忘れがちな点である。

また、波括弧を用いると、複数にわたる文からなるマクロを正しく展開するのにも役立つ。複数にわたる文からなるマクロは do-while ループで包むべきだ(「PRE10-C. 複数にわたる文からなるマクロは do-while ループで包む」を参照)。しかし、do-while ループがなくても、波括弧を使用することでマクロが意図したとおりに展開されることを保証できる。

違反コード

次のコード例は、波括弧を付けずに if 文を使用してユーザの認証を行っている。

int login;

if (invalid_login())
  login = 0;
else
  login = 1;

上記のコードにログインが有効かどうかを判定するデバッグ文を追加したときに、プログラマが開始と終了の波括弧を追加し忘れたとする。

int login;

if (invalid_login())
  login = 0;
else
  printf("Login is valid\n");  /* デバッグ行がここに追加される */
  login = 1;                   /* この行はログインが有効かどうかを問わず常に実行される */

コードの字下げが原因で、意図した通りにコードが機能しないということがわかりにくいため、セキュリティの侵害につながる可能性がある。

適合コード

次の適合コードでは、本体が単一の文であっても開始と終了の波括弧を使用している。

int login;

if (invalid_login()) {
  login = 0;
} else {
  login = 1;
}
違反コード

次のコード例では、ifelse の本体を波括弧で囲まずに、if 文の中で if 文を入れ子にしている。

int privileges;

if (invalid_login())
  if (allow_guests())
    privileges = GUEST;
else
  privileges = ADMINISTRATOR;

字下げが原因で、プログラマはユーザのログインが有効な場合に限りユーザに管理者権限が与えられると考えてしまうかもしれない。しかし、else 文は実際には内側の if 文と結び付けられている。

int privileges;

if (invalid_login())
  if (allow_guests())
    privileges = GUEST;
  else
    privileges = ADMINISTRATOR;

これはセキュリティの抜け道であり、ログインが無効のユーザでも管理者権限を取得できてしまう可能性がある。

適合コード

次の適合コードは、波括弧を追加することであいまいさを排除し、権限が正しく割り当てられることを保証している。

int privileges;

if (invalid_login()) {
  if (allow_guests()) {
    privileges = GUEST;
  } 
} else {
  privileges = ADMINISTRATOR;
}
違反コード (empty block)

以下のコードは、本体を持たない while 文である。

while (invalid_login());

invalid_login() が、ログイン失敗の警告表示などのような副作用を何も発生させないものであったならば、「MSC12-C. プログラムに対して作用しないコードを検出して削除する」にも違反していることになる。

適合コード (empty block)

以下の適合コードでは、空のブロックを置くことでプログラマーの意図を明示している。

while (invalid_login()) {}
リスク評価

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

EXP19-C

P8

L2

自動検出(最新の情報はこちら

ツール

バージョン

チェッカー

説明

Astrée
24.04

compound-ifelse

compound-loop

Fully checked
Axivion Bauhaus Suite

7.2.0

CertC-EXP19 Fully implemented
Helix QAC

2024.2

C2212
Klocwork
2024.2
MISRA.IF.NO_COMPOUND
MISRA.STMT.NO_COMPOUND

LDRA tool suite
9.7.1
11 S,  12 S, 428 S Fully Implemented
Parasoft C/C++test
2023.1
CERT_C-EXP19-a

The statement forming the body of a 'switch', 'while', 'do...while' or 'for' statement shall be a compound statement

PC-lint Plus

1.4

9012

Fully supported

Polyspace Bug Finder

R2024a

CERT C: Rec. EXP19-C

Checks for iteration or selection statement body not enclosed in braces (rec. fully covered)

PVS-Studio

7.31

V563, V628, V640, V705
RuleChecker
24.04

compound-ifelse

compound-loop

Fully checked
SonarQube C/C++ Plugin
3.11
S121
関連する脆弱性

CVE-2014-1266 was due, in large part, to failing to follow this recommendation. There is a spurious "goto fail" statement on line 631 of sslKeyExchange.c. This "goto" gets executed unconditionally, even though it is indented as if it were part of the preceding "if" statement.  As a result, the call to sslRawVerify (which performs the actual signature verification) is rendered dead code.  [ImperialViolet 2014]. If the body of the "if" statement had been enclosed in braces, then this defect likely would not have happened.

関連するガイドライン
MISRA C:2012 Rule 15.6 (required)
参考資料
[GNU 2010] Coding Standards, Section 5.3, "Clean Use of C Constructs"
翻訳元

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

EXP19-C. Use braces for the body of an if, for, or while statement (revision 92)

Top へ

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