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

EXP03-C. 構造体のサイズが構造体のメンバのサイズの和に等しいと決めてかからない

構造体のサイズは、そのメンバのサイズの和に必ずしも等しいわけではない。C 標準のセクション 6.7.2.1 には次のようにある。「構造体オブジェクトの中には名前のない詰め物があってもよいが、先頭には名前のない詰め物があってはならない。」[ISO/IEC 9899:2011]

これは構造体パディングとよばれることが多い。構造体のメンバは、プログラムテキストで宣言された順序でメモリ上に配置される。構造体がメモリ上で適切にアラインされるように、構造体にパディング(詰め物)を加えることがある。多くのアーキテクチャでは、構造体パディングをすることで構造体のメンバへのアクセスが高速化する。

structのフィールドを再配置することでstructのサイズは変わるかもしれない。同じサイズのフィールドがグループ化できるようにフィールドを配置することで、不規則なパディングが行われることを最小限に食い止めることができるかもしれない。

パディングは struct メンバアラインメントと呼ばれることもある。多くのコンパイラにはフラグが用意されており、構造体のメンバがどのようにメモリにパックされるかを制御する。このフラグを変更することで構造体のサイズは変わってくる。また、大半のコンパイラにはすべてのパディングを取り除くキーワードが用意されており、この構造体はpacked structuresと呼ばれる。デフォルトの動作を上書きすることは賢明とは言えない場合が多い。インターフェイスの互換性問題につながるからである。(コード上同じstructのレイアウトが他のモジュールにより違った形で解釈される。)

違反コード

以下のコードでは、struct buffer のサイズが各メンバのサイズの和に等しいと仮定しているが、実際にはそうではない [Dowd 2006]。struct buffer のサイズは、構造体パディングのせいで大きくなっているかもしれない。

enum { buffer_size = 50 };

struct buffer {
  size_t size;
  char bufferC[buffer_size];
} buff;

/* ... */

void func(const struct buffer *buf) {

  /*
   * sizeof(struct buffer) = sizeof(size_t) + sizeof(buff.bufferC)
   * であると間違って仮定している
   */
  struct buffer *buf_cpy = (struct buffer *)malloc(
    sizeof(size_t) + sizeof(buff.bufferC)
  );

  if (buf_cpy == NULL) {
    /* malloc() エラーの処理 */
  }

  /*
   * パディングの結果、sizeof(struct buffer) は
   * sizeof(size_t) + sizeof(buff.bufferC) より大きいかもしれない、その結果、
   * 割り当てた範囲外にデータを書きこんでしまう恐れがある
   */
  memcpy(buf_cpy, buf, sizeof(struct buffer));

  /* ... */

  free(buf_cpy);
}
適合コード

構造体パディングについて考慮することでこの手のエラーを防げる。

enum { buffer_size = 50 };

struct buffer {
  size_t size;
  char bufferC[buffer_size];
} buff;

/* ... */

void func(const struct buffer *buf) {

  struct buffer *buf_cpy = 
    (struct buffer *)malloc(sizeof(struct buffer));

  if (buf_cpy == NULL) {
    /* malloc() エラーの処理 */
  }

  /* ... */

  memcpy(buf_cpy, buf, sizeof(struct buffer));

  /* ... */

  free(buf_cpy);
}
リスク評価

構造体のサイズを正しく計算し損ねると、些細な論理エラーや計算ミスにつながる恐れがある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

EXP03-C

P2

L3

自動検出

ツール

バージョン

チェッカー

説明

LDRA tool suite

V. 8.5.4

400 S
578 S

実装済み

PRQA QA-C 8.1 0697 部分的に実装済み
関連するガイドライン
CERT C++ Secure Coding Standard EXP03-CPP. Do not assume the size of a class or struct is the sum of the sizes of its members
参考資料
[Dowd 2006] Chapter 6, "C Language Issues" ("Structure Padding," pp. 284–287)
[ISO/IEC 9899:2011] Section 6.7.2.1, "Structure and Union Specifiers"
[Sloss 2004] Section 5.7, "Structure Arrangement"
翻訳元

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

EXP03-C. Do not assume the size of a structure is the sum of the sizes of its members (revision 89)

Top へ

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