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

EXP40-C. 定数オブジェクトを変更しない

C 標準 [ISO/IEC 9899:2011] セクション 6.7.3 のパラグラフ 6 には次のように記載されている。

const 修飾型で定義されたオブジェクトを、非 const 修飾型の左辺値を使って変更しようとした場合、その動作は未定義とする。

(C 標準の附属書 J 「未定義の動作」の 64 も参照すること。)

既存のコンパイラ実装によっては、const 修飾型の値の変更を警告なしで許可するものもある。

また、const 修飾をキャストではずすと、const 修飾型の値を警告なしで容易に変更できることになるため、const 修飾をキャストではずさないことも推奨される(「EXP05-C. const 修飾をキャストではずさない」参照)。

違反コード

C 標準のセクション 6.5.16.1 から抜粋した以下のコード例は、きちんと書かれているが定数値を変更できるためルールに違反している。

char const **cpp;
char *cp;
char const c = 'A';

cpp = &cp; /* 制約違反 */
*cpp = &c; /* 正しい */
*cp = 'B'; /* 正しい */

最初の代入は安全ではない。なぜなら、その後で正しいコードによって const オブジェクト c の値を変更できるからである。

違反コード(文字列リテラルの変更)

上記の例と同様、以下のコード例はきちんと書かれているが、const 修飾をキャストではずした後 const オブジェクトを変更しているため、ルールに違反している。Linux/x64 システム上でこのプログラムをコンパイルした場合、厳しい警告レベルでも警告は発行されないが、生成された実行プログラムは実行時に SIGSEGV により失敗する。

const char s[] = "foo";
int main() {
  *(char*)s = '\0';
}
処理系固有の詳細

cppcpc が自動(スタック)変数として宣言された場合、上記のコードは、Microsoft Visual C++ .NET (2003) および MS Visual Studio 2005 では警告なしでコンパイルされる。どちらの場合も、生成されるプログラムはc の値を変更する。MS Visual Studio 2008 はエラーメッセージを表示する。GCC コンパイラのバージョン 3.2.2 は、警告を出すがコンパイルは行う。生成されるプログラムは c の値を変更する。

cppcpc が静的記憶域期間で宣言された場合、このプログラムは MS Visual Studio と GCC 3.2.2 のどちらの場合も異常終了する。

適合コード

このコード例の適合コードは、プログラマの意図によって異なる。c の値を変更することを意図している場合は、c を定数として宣言してはならない。c の値を変更することを意図していない場合は、これを変更するような違反コードを書かないこと。

リスク評価

非 const の参照を通じて const オブジェクトを変更すると、未定義の動作が引き起こされる。

ルール

深刻度

可能性

修正コスト

優先度

レベル

EXP40-C

P2

L3

参考資料
[ISO/IEC 9899:2011] Section 6.7.3, "Type Qualifiers"
翻訳元

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

EXP40-C. Do not modify constant objects (revision 57)

Top へ

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