The abstract InputStream.read()
method reads a single byte from an input source and returns its value as an int
in the range 0 to 255. It will return -1 only when the end of the input stream has been reached. The similar Reader.read()
method reads a single character, and returns its value as an int
in the range 0 to 65,535. It also returns -1 only when the end of the stream has been reached. Both methods are meant to be overridden by subclasses.
These methods are often used to read a byte or character from a stream. Unfortunately, many programmers prematurely convert the resulting int
back to a byte
or char
before checking whether they have reached the end of the stream (indicated by a return value of -1). Programs must check for the end of stream (e.g., -1) before narrowing the return value to a byte
or char
.
This rule applies to any InputStream
or Reader
subclass that provides an implementation of the read()
method. This rule is a specific instance of rule NUM12-J. Ensure conversions of numeric types to narrower types do not result in lost or misinterpreted data.
byte
)This noncompliant code example casts the value returned by the read()
method directly to a value of type byte
and then compares this value with -1 in an attempt to detect the end of the stream.
FileInputStream in; // initialize stream byte data; while ((data = (byte) in.read()) != -1) { // ... } |
If the read()
method encounters a 0xFF
byte in the file, this value is indistinguishable from the -1 value used to indicate the end of stream, because the byte value is promoted and sign-extended to an int
before being compared with -1. Consequently, the loop can halt prematurely if a 0xFF
byte is read.
byte
)Use a variable of type int
to capture the return value of the byte
input method. When the value returned by read()
is not -1, it can be safely cast to type byte
. When read()
returns 0x000000FF
, the comparison will test against 0xFFFFFFFF
, which evaluates to false
.
FileInputStream in; // initialize stream int inbuff; byte data; while ((inbuff = in.read()) != -1) { data = (byte) inbuff; // ... } |
char
)This noncompliant code example casts the value of type int
returned by the read()
method directly to a value of type char
, which is then compared with -1 in an attempt to detect the end of stream. This conversion leaves the value of data
as 0xFFFF
(e.g., Character.MAX_VALUE
) instead of -1. Consequently, the test for the end of file never evaluates to true.
FileReader in; // initialize stream char data; while ((data = (char) in.read()) != -1) { // ... } |
char
)Use a variable of type int
to capture the return value of the character input method. When the value returned by read()
is not -1, it can be safely cast to type char
.
FileReader in; // initialize stream int inbuff; char data; while ((inbuff = in.read()) != -1) { data = (char) inbuff; // ... } |
Historically, using a narrow type to capture the return value of a byte input method has resulted in significant vulnerabilities, including command injection attacks; see CA-1996-22 advisory. Consequently, the severity of this error is high.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FIO08-J |
high |
probable |
medium |
P12 |
L1 |
Some static analysis tools can detect violations of this rule.
FIO34-C. Use int to capture the return value of character IO functions |
|
FIO34-CPP. Use int to capture the return value of character IO functions |
[API 2006] |
Class |
[JLS 2005] |
§4.2 Primitive Types and Values |
Waiting for the End |