FLP34-C. 浮動小数点の型変換は変換後の型の範囲に収まるようにする
浮動小数点型の値が範囲と精度の低い別の浮動小数点型あるいは整数型に変換される場合や、整数型が浮動小数点型に変換される場合、値は変換後の型で表現できるものでなくてはならない。
C 標準、6.3.1.4節、第1パラグラフには次のように記されている [ISO/IEC 9899:2011]。
実浮動小数点型の有限の値を
_Bool
型以外の整数型に型変換する場合、小数部を捨てる(すなわち、値を0
方向に切り捨てる)。整数部の値が整数型で表現できない場合、その動作は未定義とする。
同節の第2パラグラフには次のように記されている。
整数型の値を実浮動小数点型に型変換する場合、変換する値が新しい型で正確に表現できるとき、その値は変わらない。変換する値が表現しうる値の範囲内にあるが正確に表現できないならば、その値より大きく最も近い表現可能な値、またはその値より小さく最も近い表現可能な値のいずれかを処理系定義の方法で選ぶ。変換する値が表現しうる値の範囲外にある場合、その動作は未定義とする。
また、6.3.1.5 節の第1パラグラフには次のように記されている。
実浮動小数点型の値を実浮動小数点型に型変換する場合、変換する値が新しい型で正確に表現できるとき、その値は変わらない。変換する値が、表現しうる値の範囲内にあるが正確に表現できない場合、その結果は、その値より大きく最も近い表現可能な値、またはその値より小さく最も近い表現可能な値のいずれかを処理系定義の方法で選ぶ。変換する値が表現しうる値の範囲外にある場合、その動作は未定義とする。
詳しくは、C 標準の附属書の未定義の動作 17 および 18 を参照。
IEEE 754 のように符号付き無限大をサポートする処理系においては、すべての数が範囲内にあるため、浮動小数点型の降格にこのルールは適用されない。
違反コード (float
から int
)
次の違反コード例では、f_a
の整数部が整数型として表現できない場合、未定義の動作となる。
void func(float f_a) {
int i_a;
/* f_a の整数部 >= INT_MAX のとき未定義 */
i_a = f_a;
}
適合コード (float
から int
)
次の適合コードでは、float
型の値の範囲が int
の値の範囲より大きいことを前提としている(多くの処理系ではそうである)。残念なことに、この前提が成り立っているかどうかをコード中で安全に確認する方法はない。多くの処理系では INT_MAX
を float
に変換すると、元の INT_MAX
の値よりも 1
大きな値になってしまう。同様に多くの処理系では、INT_MIN
を float
に変換すると、元の INT_MIN
の値よりも 1
小さな値になってしまう。
#include <float.h>
#include <limits.h>
void func(float f_a) {
int i_a;
if (f_a >= ((float)INT_MAX -1.0) || f_a < ((float)INT_MIN +1.0)|| (f_a >= 0.0F && f_a < FLT_MIN)) {
/* エラー処理 */
} else {
i_a = f_a;
}
}
違反コード (精度が低い型への変換)
次の違反コード例では、値が変換後の型の範囲外になりうる変換を行っている。
void func(double d_a, long double big_d) {
double d_b = (float)big_d;
float f_a = (float)d_a;
float f_b = (float)big_d;
}
これらの変換において、d_a
は float で表現できる値の範囲を超えている可能性がある。また big_d
は float
や double
で表現できる値の範囲を超えている可能性がある。その場合、付属書 F "IEC 60559 Floating-Point Arithmetic." をサポートしない処理系において、変換結果は未定義となる。
適合コード (精度が低い型への変換)
次の適合コードでは、格納する値が新しい型で表現可能かどうかを確認している。
#include <float.h>
void func(double d_a, long double big_d) {
double d_b;
float f_a;
float f_b;
if (isgreater(d_a, FLT_MAX) || isless(d_a, FLT_MIN)) {
/* エラー処理 */
} else {
f_a = (float)d_a;
}
if (isgreater(big_d, FLT_MAX) || isless(big_d, FLT_MIN)) {
/* エラー処理 */
} else {
f_b = (float)big_d;
}
if (isgreater (big_d, DBL_MAX) || isless(big_d, DBL_MIN)) {
/* エラー処理 */
} else {
d_b = (double)big_d;
}
}
リスク評価
浮動小数点型の値を範囲と精度の低い浮動小数点型、あるいは、整数型に変換したり、整数型を浮動小数点型に変換したりすると、変換後の型で値を表現できない値になったり、付属書Fをサポートしない処理系においては未定義の動作になる可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
FLP34-C |
低 |
低 |
低 |
P3 |
L3 |
自動検出
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
|
|
このルールの違反を検出できる。しかし、暗黙的なキャストは検出せず、明示的キャストのみ検出する |
|
7.5.0 |
MISRA_CAST |
暗黙の float 変換が行われる場合を検出できる。たとえば、整数型から浮動小数点型への複雑な式の暗黙の変換、double 式からより狭い浮動小数点型への暗黙の変換 (精度が失われる場合がある)、 |
|
5.0 |
|
CERT C Rule Packを使ってこのルールの違反を検出できる |
|
PRQA QA-C | v8.2 |
4450 4462 4465 |
部分的に実装済み |
関連するガイドライン
CERT C++ Coding Standard | VOID FLP34-CPP. Ensure that floating point conversions are within range of the new type |
Java セキュアコーディングスタンダード CERT/Oracle 版 | NUM12-J. 数値型の縮小変換時にデータの欠損や誤解釈を引き起こさない |
ISO/IEC TR 24772:2013 | Numeric Conversion Errors [FLC] |
MITRE CWE | CWE-681, Incorrect Conversion between Numeric Types |
参考資料
[IEEE 754 2008] | |
[ISO/IEC 9899:2011] | 6.3.1.4, "Real Floating and Integer" 6.3.1.5, "Real Floating Types" |
翻訳元
これは以下のページを翻訳したものです。
FLP34-C. Ensure that floating-point conversions are within range of the new type (revision 116)