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

ARR02-C. 初期化子が暗黙的にサイズを定義する場合であっても、配列のサイズは明示的に指定する

C 言語規格上、配列変数は、サイズと初期化リテラルの両方を使って宣言してよい。初期化リテラルで指定された要素数からは、配列のサイズが分かる。

初期化リテラルが暗黙的に示す配列サイズは、通常、要素の数で指定される。

int array[] = {1, 2, 3}; /* 3 つの要素からなる配列 */

一方、指示子を使って配列要素が連続しない形で初期化することもできる。C 言語規格 [ISO/IEC 9899:2011] のセクション 6.7.9 例 12 には、次のように書かれている。

要素指示子を一つだけ使うことで、配列の両端に初期値を与えることができる。

int a[MAX] = {
  1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};

この例において MAX が 10 より大きい場合、配列中央に値 0 の要素が幾つかの存在することになる。MAX が 10 よりも小さい場合、先頭の 5 個の初期化子で与えられた値の幾つかを後半の 5 個の初期化子が上書きする。

C 言語規格 はまた、初期化子の数と配列の明示的なサイズが異なるときに、どのように配列が初期化されるを定めている。セクション 6.7.9 の第 21 および 22 パラグラフには次のように書かれている。

集成体型の要素又はメンバの個数より波括弧で囲まれた並びにある初期化子が少ない場合、又は大きさが既知の配列の要素数よりその配列を初期化するための文字列リテラル中の文字数が少ない場合、その集成体型の残りを、静的記憶域期間を持つオブジェクトと同じ規則で暗黙に初期化する。

サイズが決まっていない配列を初期化する場合、配列のサイズは、明示的な初期化子の、最も大きなインデックスで参照される要素によって決定される。初期化子並びの終了時点では、配列型は完全である。

コンパイラは初期化子並びに基づいて配列のサイズを計算することができるが、配列のサイズを明示的に指定しておくことで、冗長ではあるがい、配列サイズが正しいことを確認できる。さらに、配列サイズが初期化子によって示されるサイズより小さい場合に警告を出すこともできる。

このレコメンデーションは、文字列リテラルを使って初期化される文字配列には適用されない点に注意。詳細については「STR36-C. 文字列リテラルで初期化される文字列のサイズを指定しない」を参照。

違反コード (サイズが正しくない)

以下の違反コード例では、整数配列を初期化しているが、要素の数が多すぎる。

int a[3] = {1, 2, 3, 4};

配列 a のサイズは 3 だが、初期化サイズは 4 である。初期化の最後の要素(4)は無視される。ほとんどのコンパイラはこれをエラーと診断する。

処理系固有の詳細

GCC はこのコードに対して警告を発する。Microsoft Visual Studio は次のようなコンパイルエラーになる。エラー C2078: 初期化子の数が多すぎます.

違反コード (サイズが明示的でない)

この違反コード例では、コンパイラは 4 つの整数からなる配列を割り当てている。配列のサイズは、明示的に指定されていないため、4 に設定される。ただし、初期化子が変わると配列のサイズも変わり、予期せぬ結果を引き起こす。

int a[] = {1, 2, 3, 4};
適合コード

以下の適合コードは、配列範囲を明示的に指定している。

int a[4] = {1, 2, 3, 4};

配列のサイズは、初期化子によって暗黙的に定義されてはいるが、明示的に指定しておくことで、数が一致しない場合にコンパイラやその他の静的分析ツールが診断メッセージを出力することができる。

例外

ARR02-EX1: 「STR36-C. 文字列リテラルで初期化される文字配列のサイズを指定しない」は、このレコメンデーションの例外に該当する。このルールは文字列リテラルで初期化される文字配列のサイズを指定しないことを要求する。

リスク評価

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

ARR02-C

P6

L2

自動検出

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

 

ECLAIR

1.1

araydecl

実装済み

LDRA tool suite

V. 8.5.4

127 S
397 S
404 S

部分的に実装済み

PRQA QA-C 8.1

0684 (C)
0686
0687
0688
3674
3684

実装済み
関連するガイドライン
CERT C++ Secure Coding Standard ARR02-CPP. Explicitly specify array bounds, even if implicitly defined by an initializer
MITRE CWE CWE-665, Incorrect or incomplete initialization
参考資料
[ISO/IEC 9899:2011] Section 6.7.9, "Initialization"
翻訳元

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

ARR02-C. Explicitly specify array bounds, even if implicitly defined by an initializer (revision 44)

Top へ

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