抽象メソッド InputStream.read() は、入力ストリームから1バイト読み取り、読み取った値を0から255の範囲にある int 型データとして返す。入力ストリームの終端に達した場合、メソッドは -1 を返す。同様に、Reader.read() メソッドは1文字読み取り、読み取った値を0から65,535の範囲にある int 型データとして返す。ストリームの終端に達した場合にのみ、同様に -1 を返す。いずれのメソッドもサブクラスによってオーバーライドされることを意図している。
プログラマは多くの場合、これらのメソッドを使用してストリームからバイトや文字データを読み取る。しかし、ストリームの終端に達したかどうかをチェックする前に(返り値が-1)、int である返り値を byte や char に変換してしまう例が見られる。正しくは、返り値を byte や char などビット幅の狭い型に変換する前に、ストリームの終端を示していないか(例: -1)チェックしなくてはならない。
このルールは、read() メソッドを実装するすべての InputStream および Reader のサブクラスに適用される。なお、このルールは「NUM12-J. 数値型の縮小変換時にデータの欠損や誤解釈を引き起こさない」の具体例である。
違反コード (byte)
以下の違反コード例では、read() メソッドの返り値をまず byte 型の値に変換し、そのあとで値を -1 と比較し、ストリームの終端に達していないかどうかをチェックしている。
FileInputStream in; // 入力ストリームを初期化 byte data; while ((data = (byte) in.read()) != -1) { // ... }
read() メソッドが byte 値 0xFF を返す場合、ストリームの終端を示す値である -1 と見分けがつかなくなる。読み取られたバイトデータは、-1 と比較されるまえに符号拡張され int 型に格上げされるからである。そのため、0xFF バイトが読み取られると、そこでループは終了してしまう。
適合コード (byte)
byte データを読み取るメソッドの返り値は、int 型の変数で受けとること。read() が 0x000000FF を返すと、0xFFFFFFFF との比較が行われ、その結果は false となる。
FileInputStream in; // 入力ストリームを初期化 int inbuff; byte data; while ((inbuff = in.read()) != -1) { data = (byte) inbuff; // ... }
違反コード (char)
以下の違反コード例では、read() メソッドが返す int 型の値を直接 char 型に変換し、次に -1 と比較することでストリームの終端に達していないかどうかをチェックしている。(読み取ったデータが 0xFFFF であった場合)キャストの結果、data の値は -1 ではなく、0xFFFF (たとえば Character.MAX_VALUE)になる。それゆえ、入力がファイルの終端に達していないかのチェックが true に評価されることはない。
FileReader in; // 入力ストリームを初期化 char data; while ((data = (char) in.read()) != -1) { // ... }
適合コード (char)
文字データを読み取るメソッドの返り値は int 型の変数で受け取ること。read() の返り値が -1 でない場合、値は安全に char にキャストできる。
FileReader in; // 入力ストリームを初期化 int inbuff; char data; while ((inbuff = in.read()) != -1) { data = (char) inbuff; // ... }
リスク評価
バイトデータを読み取るメソッドの返り値をビット幅の狭い型で受け取ることが原因で、コマンドインジェクション攻撃を可能にする深刻な脆弱性につながった例が過去に存在する。詳しくは、CERT アドバイザリ CA-1996-22 を参照。それゆえ、このコーディングエラーの深刻度は高い。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO08-J | 高 | 中 | 中 | P12 | L1 |
自動検出
このルールの違反を検知できる静的解析ツールは存在する。
関連ガイドライン
CERT C Secure Coding Standard | FIO34-C. Use int to capture the return value of character IO functions |
CERT C++ Secure Coding Standard | FIO34-CPP. Use int to capture the return value of character IO functions |
参考文献
[API 2006] | Class InputStream |
[JLS 2005] | §4.2 Primitive Types and Values |
[Pugh 2008] | Waiting for the End |
翻訳元
これは以下のページを翻訳したものです。
FIO08-J. Use an int to capture the return value of methods that read a character or byte (revision 82)