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

FIO09-J. 0から255の範囲に収まらない整数値を出力するときには write() メソッドを信用しない

java.io.OutputStream クラスで定義されている write() メソッドは int 型の引数をとるが、その値は 0 から 255 の範囲でなければならない。int 型の値はこの範囲を越えることがあるので、範囲チェックを怠ると、引数の上位ビットの切り捨てを招く。

write() メソッドの一般契約は、出力ストリームに1バイト書き込む、というものである。書き込むべき1バイトには、write() メソッドの引数 b の下位8ビットが使われ、残り24ビットは無視される(詳しくは [API 2006] java.io.OutputStream.write() を参照)。

違反コード

以下の違反コード例は、ユーザ入力を検証せずに使っている。0から255の範囲に収まらない値の場合切り捨てが発生する。たとえば ASCII ベースのシステムにおいては、write(303) という呼び出しは / を表示する。なぜならば、303 の上位24ビットは無視され、下位8ビットが使われるからだ(303 % 256 = 47 であり、これは / の文字コード)。つまり、結果は 256 で割った余りとなっている。

class ConsoleWrite {
  public static void main(String[] args) { 
    // 入力が 255 より大きいと予期せぬ出力となる
    System.out.write(Integer.valueOf(args[0]));
    System.out.flush();
  }
}
適合コード (入力の範囲チェック)

以下の適合コードでは、入力された整数が適切な範囲の値であるときのみ、その値に対応する文字を出力する。入力が int 型で表現できない範囲の値だったときには、Integer.valueOf() メソッドは NumberFormatException 例外を投げる。入力が int 型で表現できる値であるが、write() が想定する範囲の値でない場合には、このコードは ArithmeticException 例外を投げる。

class FileWrite {
  public static void main(String[] args)
                          throws NumberFormatException, IOException { 
    // 範囲チェック
    int value = Integer.valueOf(args[0]);
    if (value < 0 || value > 255) {
      throw new ArithmeticException("Value is out of range");
    }
  
    System.out.write(value);
    System.out.flush(); 
  }
}
適合コード (writeInt())

以下の適合コードでは、DataOutputStream クラスの writeInt() メソッドを使っている。このメソッドは、int 型で表現できるすべての値に対応できる。

class FileWrite {
  public static void main(String[] args)
                          throws NumberFormatException, IOException { 
    DataOutputStream dos = new DataOutputStream(System.out);
    dos.writeInt(Integer.valueOf(args[0].toString()));
    System.out.flush(); 
  }     
}
リスク評価

0から255の範囲に収まらない整数値の出力に write() メソッドを使うと、切り捨てが発生する。

ルール 深刻度 可能性 修正コスト 優先度 レベル
FIO09-J P2 L3
自動検出

write() メソッドの使用を自動検出するのは簡単である。切り捨ての発生が、プログラマが意図した動作かどうかを適切に判別するのは、一般には難しい。ヒューリスティックなチェックが役に立つかもしれない。

関連ガイドライン
MITRE CWE CWE-252. Unchecked return value
参考文献
[API 2006] Method write()
[Harold 1999]  
翻訳元

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

FIO09-J. Do not rely on the write() method to output integers outside the range 0 to 255 (revision 72)

Top へ

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