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-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 (signaled by a return value of -1). Programs must check for 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 provide an implementation of the read() method.  This rule is a specific instance of 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) { 
  // ... 
}
 | 
When the read() method in this noncompliant code example returns the byte value 0xFF, it will be 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.
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 0XFF, the comparison will test 0x000000FF against 0xFFFFFFFF and fail.
| 
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 c as 0xffff (e.g., Character.MAX_VALUE) instead of -1. Consequently, the test for the end of stream never evaluates to true.
| 
FileReader in;
// initialize stream 
char c;
while ((c = (char) in.read()) != -1) { 
  // ... 
}
 | 
char)Use a variable of type int to capture the return value of the character input method. When the value of 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 function 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 | 
FindBugs version 1.3.9 can detect violations of this rule with the INT: Bad comparison of nonnegative value with negative constant detector.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
| C Secure Coding Standard | FIO34-C. Use int to capture the return value of character IO functions | 
| C++ Secure Coding Standard | FIO34-CPP. Use int to capture the return value of character IO functions | 
| <ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="b960282c-63d5-44fc-bd2b-a802493cc746"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] |  Class  | ]]></ac:plain-text-body></ac:structured-macro> | |
| <ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="75c5322b-9070-475f-acf9-ee0bc0d5a432"><ac:plain-text-body><![CDATA[ | [[JLS 2005 | AA. Bibliography#JLS 05]] | [Section 4.2 | http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2] "Primitive Types and Values" | ]]></ac:plain-text-body></ac:structured-macro> | 
| <ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="cd66012d-3f07-45e9-96e2-41cbb1f65b6f"><ac:plain-text-body><![CDATA[ | [[Pugh 2008 | AA. Bibliography#Pugh 08]] | "Waiting for the end" | ]]></ac:plain-text-body></ac:structured-macro> |