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

INT12-C. 式中で使用される単なるintのビットフィールドの型について勝手な想定をしない

ビットフィールドを使用することで、フラグ値やごく狭い範囲の値しか取らない整数値をひとまとめにしてメモリ領域を節約することができる。

ビットフィールドについて、型 intsigned int と同じ型を意味するか、あるいは unsigned int と同じ型を意味するかは処理系定義である。また、C標準 [ISO/IEC 9899:2011] では、整数拡張について次のように記載されている: 「元の型のすべての値を int で表現可能な場合(ビットフィールドの場合とりうる値の範囲はビット幅によって決まる)、int 型に変換する。そうでない場合、unsigned int 型に変換する。」

この問題は「INT07-C. 数値には符号の有無を明示した文字型のみを使用する」で議論した「単なる」 char の符号にまつわる問題に類似している。符号無しとして扱われる「単なる」 int 型ビットフィールドは、フィールド幅が int よりも小さい限り、int 型に拡張される。なぜなら int 型で元の型のすべての値を保持できるからである。これは「単なる」 char が符号無しとして扱われるのと同じ動作である。しかし、符号無しとして扱われる「単なる」 int 型ビットフィールドは、フィールド幅が int と等しい場合、unsigned int に拡張される。この違いゆえに、「単なる」 int 型ビットフィールドは「単なる」 char よりもやっかいなのである。

_Boolintsigned intunsigned int 以外のビットフィールドは処理系定義である。これらは、指定されたフィールド幅が少なくとも CHAR_BIT*sizeof(int) と同じ幅であれば、上に引用した整数拡張に従う。しかし、より広いフィールド幅は移植性が低い。

違反コード

以下のコードは処理系定義の動作に依存している。「単なる」 int 型ビットフィールドが符号付きか符号無しかにより、-1255 のいずれかを出力する。

struct {
  int a: 8;
} bits = {255};

int main(void) {
  printf("bits.a = %d.\n", bits.a);
  return 0;
}
適合コード

以下の適合コードでは、unsigned int 型ビットフィールドを使っており、処理系定義の動作に依存していない。

struct {
  unsigned int a: 8;
} bits = {255};

int main(void) {
  printf("bits.a = %d.\n", bits.a);
  return 0;
}
リスク評価

ビットフィールドの型やレイアウトについて勝手な思い込みをすると、予期せぬプログラムの欠陥につながるおそれがある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

INT12-C

P2

L3

自動検出

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

 

ECLAIR

1.1

bitftype

実装済み

LDRA tool suite

V. 8.5.4

73 S

実装済み

PRQA QA-C 8.1 0634 (I) 実装済み
関連するガイドライン
CERT C++ Secure Coding Standard INT12-CPP. Do not make assumptions about the type of a plain int bit-field when used in an expression
ISO/IEC TR 24772:2013 Bit Representations [STR]
MISRA-C Rule 12.7
参考資料
[ISO/IEC 9899:2011] Section 6.3.1.1, "Boolean, Characters, and Integers"
翻訳元

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

INT12-C. Do not make assumptions about the type of a plain int bit-field when used in an expression (revision 76)

Top へ

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