浮動小数点数は3つの例外値、infinity、-infinity、NaN(not-a-number)をとることがある。これらの値は、ゼロ除算のような例外的あるいは解決不能な浮動小数点数演算の結果として生成されることもあれば、Double.valueOf(String s)メソッドなどを通じて直接ユーザ入力から取得されることもある。これらの例外値を検出し処理しないと、プログラムの不安定な動作につながる。
Double.valueOf(String s)メソッドは、NaN、infinity、あるいは -infinity を返すことがある。プログラムは、すべての浮動小数点入力値(特にユーザから取得する値)にこれらの例外値が含まれないことを確認しなくてはならない。Double.isNaN(double d)やDouble.isInfinite(double d)メソッドをこの確認のために利用することができる。
NaN値は順序付けられていない(unordered)ため、特に問題となりやすい。たとえば、式 NaN == NaNは常にfalseを返す(「NUM07-J. NaNとの比較を行わない」を参照)。
違反コード
以下の違反コードはユーザデータを検証せずに受け取っている。
double currentBalance; // ユーザの預金残高
 
void doDeposit(String userInput) {
  double val;
  try {
    val = Double.valueOf(userInput);
  }
  catch (NumberFormatException e) {
    // 入力フォーマットエラーの処理
  }
 
  if (val >= Double.MAX_VALUE - currentBalance) {
    // 範囲エラーの処理
  }
 
  currentBalance += val;
}
valに例外値が代入され、その値が後に演算や制御値として使用される場合、このコードは予期せぬ結果をもたらす。たとえばユーザは、infinityやNaNといった文字列をコマンドラインに入力することができ、Double.valueOf(String s)によって浮動小数点数表現であるinifinityやNaNとして解釈される。後でこれらの値を使う演算は無効になり、場合によっては実行時例外を引き起こしたり、サービス運用妨害(DoS)攻撃を可能にするであろう。
前述の違反コード例では、valにNaNが代入されるとcurrentBalanceの値もNaNになり、不正な値となる。この値が別の式で使われると、その式の結果の値もNaNになり、これは重要なデータを破壊することになるかもしれない。
適合コード
以下の適合コードでは、浮動小数点数の入力値を検査してから使用している。値はinfinity、-infinity、NaNでないことが確認されている。
double currentBalance; // ユーザの預金残高
 
void doDeposit(String s){
  double val;
  try {
    val = Double.valueOf(userInput);
  }
  catch(NumberFormatException e) {
    // 入力フォーマットエラーの処理
  }
 
  if (Double.isInfinite(val)){
    // infinity エラーの処理
  }
 
  if (Double.isNaN(val)) {
    // NaN エラーの処理
  }
 
  if (val >= Double.MAX_VALUE - currentBalance) {
    // 範囲エラーの処理
  }
  currentBalance += val;
}
例外
NUM08-EX0: NaN、infinity、-infinityはプログラムが予期する入力として受け取られる場合もあるだろう。その場合、明示的なチェックは必要ないかもしれないが、これらの例外値を適切に処理し、例外値を処理できない別のコードに値を渡さないようにしなくてはならない。また、例外値をプログラムの通常動作時の入力として認める選択をしたことを明文化すべきである。
リスク評価
浮動小数点数入力の検査が間違っていたりそもそも検査しないと、計算間違いや予期せぬ結果につながり、結果的にプログラムの誤動作やサービス運用妨害(DoS)が起こる恐れがある。
| ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル | 
|---|---|---|---|---|---|
| NUM08-J | 低 | 中 | 中 | P4 | L3 | 
自動検出
一般に自動検出は不可能である。汚染解析のような手法を使うことで、危険なケースを多数検出できるであろう。
関連する脆弱性
HARMONY-6242, HARMONY-6268
関連ガイドライン
| The CERT C Secure Coding Standard | FLP04-C. Check floating point inputs for exceptional values | 
| The CERT C++ Secure Coding Standard | FLP04-CPP. Check floating point inputs for exceptional values | 
参考文献
| [IEEE 754] | 
| [IEEE 1003.1, 2004] | 
翻訳元
これは以下のページを翻訳したものです。
NUM08-J. Check floating-point inputs for exceptional values (revision 63)
