EXP44-C. sizeof 演算子のオペランドは副作用を持たせない
sizeof
演算子の結果は、そのオペランドのサイズ(バイト)とする。オペランドは、式または括弧で囲まれた型の名前のいずれかとする。オペランドの型が可変長配列型 (VLA) である場合は式が評価され、この型でない場合はオペランドは評価されない。
sizeof
演算子のオペランドの部分が VLA 型で、VLA のサイズの値を変更しても演算子の結果に影響しない場合、サイズが評価されるかどうかは指定されない。C 標準の附属書 J、セクション J.1 の「未規定の動作」の 22 を参照すること [ISO/IEC 9899:2011]。
副作用を生成するような式は、VLA 以外の場合にそのような式が評価されず、未規定の結果が発生するということを知らないプログラマに混乱を与える恐れがある。その結果、プログラマはプログラムの実行状態について誤った仮定をしてしまい、エラーやソフトウェアの脆弱性につながる恐れがある。
違反コード
以下のコード例では、式 a++
は評価されず、式中の副作用は実行されない。
int a = 14; int b = sizeof(a++);
したがって、b
が初期化された後の a
の値は 14 である。
処理系固有の詳細
このコード例は Microsoft Visual Studio 2005 Version 8.0 に /W4 オプションをつけてコンパイルすると警告はでない。
適合コード
以下の適合コードでは、変数 a
をインクリメントしている。
int a = 14; int b = sizeof(a); a++;
違反コード (可変長配列)
以下のコード例では、a
の初期化における式 ++n
は、sizeof
演算子の VLA オペランドのサイズに影響を及ぼすため、評価する必要がある。しかし、n
の値に関係なく式 ++n % 1
は0
となるため、この値は sizeof
演算子の結果に影響しない。そのため、n
がインクリメントされるかどうかは指定されない。
void f(size_t n) { size_t a = sizeof(int [++n]); /* n のインクリメントが必要 */ size_t b = sizeof(int [++n % 1 + 1]); /* n のインクリメントは不要 */ /* ... */ }
適合コード (可変長変数)
以下のコード例では、sizeof
式で使用される変数 n
の値は変更せず、代わりに外部で安全にインクリメントしている。
void f(size_t n) { size_t a = sizeof(int [n + 1]); ++n; size_t b = sizeof(int [n % 1 + 1]); ++n; /* ... */ }
リスク評価
副作用を生成するようにみえる式を sizeof
演算子に渡すと、結果は期待した値と異なるかもしれない。結果の値の利用如何によっては、意図せぬプログラムの動作につながる恐れがある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
EXP44-C |
低 |
低 |
低 |
P3 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
|
|
|
ECLAIR |
1.1 |
unexfct |
実装済み |
LDRA tool suite |
V. 8.5.4 |
54 S |
実装済み |
PRQA QA-C | 8.1 | 3307 | 実装済み |
関連するガイドライン
CERT C++ Secure Coding Standard | EXP06-CPP. Operands to the sizeof operator should not contain side effects |
CERT C++ Secure Coding Standard | EXP06-CPP. Operands to the sizeof operator should not contain side effects |
翻訳元
これは以下のページを翻訳したものです。
EXP44-C. Operands to the sizeof operator should not contain side effects (revision 58)