INT17-C. 処理系に依存しない方法で整数定数を定義する
整数定数はマスクや特定のビット値として使用されることが多い。これらの定数は、 マシン上でデータがどのように表現されるかを示すために16進数で表現されることが多い。しかし、16進整数定数は可搬性のない方法で使用されることが少なくない。
違反コード
教育目的で示す下記の違反コード例では、flipbits()
関数において、x
の値をビット反転するために、全ビットが 1 であるマスクに対してビット単位の排他 OR を実行している。unsigned long
型が 32 ビット値で表される処理系の場合、x
の各ビットは正しく反転される。
/* (誤り) mask の全てのビットを1に設定する */ const unsigned long mask = 0xFFFFFFFF; unsigned long flipbits(unsigned long x) { return x ^ mask; }
しかし、unsigned long
型の値が 32 ビットより大きいビット幅で表される処理系では、mask
の上位ビットにゼロが付く。たとえば、unsigned long
型の値が64ビット長であるような処理系では、mask
には 0x00000000FFFFFFFF
が代入される。このため、x
の下位ビットのみが反転される。
適合コード (−1
)
この適合コードでは、整数定数 -1
を使用して、mask
のすべてのビットを 1 に設定している。整数定数 -1
は signed int
型である。-1
は unsigned long
型で表現できないため、C標準 [ISO/IEC 9899:2011] 6.3.1.3項、第2パラグラフのルールに従い、表現可能な数値に変換される。
[値を新しい型で表現できない場合] 新しい型が符号無しの場合は、値が新しい型の範囲内になるまで、新しい型で表現できる最大値より 1 大きい値の加算または減算を繰り返して値を変換する。
「新しい型で表現可能な最大値より 1 大きい」 ULONG_MAX + 1
に -1
が加算された結果が右側の値 ULONG_MAX
になる。ULONG_MAX
の表現は、セクション 6.2.6.2 第 1 パラグラフによってすべてのビットが 1 になることが保証されている。
unsigned char
型以外の符号無し整数型の場合、オブジェクト表現のビットは、値ビットとパディングビット(後者は必須ではない)2つのグループに分けられる。N 値ビットがある場合、各ビットは 1 ~ 2N − 1 までの異なる 2 のべき乗を表すため、その型のオブジェクトは純 2 進表記法を使用して 0 ~ 2N − 1 までの値を表すことができる。これは値表現として知られている。パディングビットの値は未指定である。
同じ理由で、-1
は、符号無し整数変数のすべてのビットを 1 に設定する用途に適している。6.2.6.1 項、第 3 パラグラフにより、unsigned char
型でも同じ結果になることが保証されている。
符号無しビットフィールドと
unsigned char
型のオブジェクトに格納される値は純 2 進表記法を使用して表現される。
/* (正しい) mask の全てのビットを1に設定する */ const unsigned long mask = -1; unsigned long flipbits(unsigned long x) { return x ^ mask; }
違反コード
以下のコード例では、プログラマは最上位ビットを立てようとしている。
const unsigned long mask = 0x80000000; unsigned long x; /* x を初期化 */ x |= mask;
このコードは unsigned long
が32ビットであるような処理系では期待通りに動作するが、精度が64ビットの unsigned long
の場合はそうではない。
適合コード
上位ビットを立てる可搬性のある(かつ安全な)方法は、以下のようにシフト式を用いることである。
const unsigned long mask = ~(ULONG_MAX >> 1); unsigned long x; /* x を初期化 */ x |= mask;
リスク評価
コードを移植する際に脆弱性が入り込むことは少なくない。たとえばバッファオーバーフローの脆弱性は、誤って定義された整数定数を使ってバッファのサイズを計算する場合に発生することがある。可搬性のあるコードを書くことは常に望ましいが、特に性能上のオーバーヘッドが発生しない場合にはそうすべきである。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
INT17-C |
高 |
中 |
低 |
P18 |
L1 |
関連するガイドライン
CERT C++ Secure Coding Standard | INT17-CPP. Define integer constants in an implementation-independent manner |
参考資料
[Dewhurst 2002] | Gotcha #25, "#define Literals" |
[ISO/IEC 9899:2011] | Subclause 6.2.6, "Representation of Types" Subclause 6.3.1.3, "Signed and Unsigned Integers" |
翻訳元
これは以下のページを翻訳したものです。
INT17-C. Define integer constants in an implementation-independent manner (revision 32)