Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The abstract InputStream.read() and Reader.read() methods are used to read a byte or character, respectively, from a stream. The  InputStream.read() method reads a single byte from an input source and returns its value as an int in the range 0 to 255 (0x00-0xff). The Reader.read() method reads a single character and returns its value as an int in the range 0 to 65,535 (0x0000-0xffff). Both methods return the 32-bit value -1 (0xffffffff) to indicate that the end of the stream has been reached and no data is available. The larger int size is used by both methods to differentiate between the end-of-stream indicator and the maximum byte (0xff) or character (0xffff) value. The end-of-stream indicator is an example of an in-band error indicator. In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged.

Prematurely converting the resulting int to a byte or char before testing for the value −1 makes it impossible to distinguish between characters read and the end of stream indicator. Programs must check for the end of stream before narrowing the return value to a byte or char.

This rule applies to any method that returns the value −1 to indicate the end of a stream. It includes any InputStream or Reader subclass that provides 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.

Noncompliant Code Example (byte)

FileInputStream is a subclass of InputStream. It will return −1 only when the end of the input stream has been reached. 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.

Code Block
bgColor#FFcccc
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 becomes 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 will halt prematurely if a 0xFF byte is read.

Compliant Solution (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.

Code Block
bgColor#ccccff
FileInputStream in;
// Initialize stream 
int inbuff;
byte data;
while ((inbuff = in.read()) != -1) { 
  data = (byte) inbuff;
  // ...  
}

Noncompliant Code Example (char)

FileReader is a subclass of InputStreamReader, which is in turn a subclass of Reader. It also returns −1 only when the end of the stream is reached. This noncompliant code example casts

Wiki Markup
The {{char}} type is the only unsigned primitive type in Java. As a result, a signed value cannot be stored and retrieved successfully from a variable of type {{char}}. In particular, comparing a value of type {{char}} with -1 will never yield {{true}}.  However, because the method {{read()}} returns -1 to indicate {{EOF}}, it is tempting to compare the character returned by {{read()}} with -1.  This is a common error \[[Pugh 08|AA. Java References#Pugh 08]\].

Noncompliant Code Example

In this noncompliant code example, the value of type int returned by the read() method is cast directly to a value of type char, which is then compared with -1 to try to detect EOF−1 in an attempt to detect the end of stream. This conversion leaves the value of c data as 0xffff 0xFFFF (e.g., Character.MAX_VALUE) instead of -1. As a result, this test −1. Consequently, the test for the end of file never evaluates to true.

Code Block
bgColor#FFcccc
FileReader in;
// Initialize stream 
char cdata;
while ((cdata = (char) in.read()) != -1) { 
  // ... 
}

Compliant Solution (char)

Always use Use a signed type of sufficient size to store signed data. To be compliant, use a value of type int to check for EOF while reading in data. If the value of type int variable of type int to capture the return value of the character input method. When the value returned by read() is not -1−1, then it can be safely cast to a value of type char.

Code Block
bgColor#ccccff
FileReader in;
// Initialize stream 
int inbuff;
char cdata;
while ((cinbuff = in.read()) != -1) {ch 
  data = (char)c inbuff;
  // ...  
}

Risk Assessment

Storing signed data in a variable of the unsigned type char can lead to misinterpreted data and possibly memory leaks. Furthermore, comparing a value of type char with -1 never evaluates to true. This error could lead to a denial-of-service attackHistorically, 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

INT35

FIO08-J

low

High

unlikely

Probable

low

Medium

P3

P12

L3

L1

Automated Detection

FindBugs version 1.3.9 Some static analysis tools can detect violations of this rule with the INT: Bad comparison of nonnegative value with negative constant detector.

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

This rule appears in the C Secure Coding Standard as FIO34-C. Use int to capture the return value of character IO functions.

...

.

ToolVersionCheckerDescription
Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.FIO08.CRRVCheck the return value of methods which read or skip input
SpotBugs

Include Page
SpotBugs_V
SpotBugs_V

EOS_BAD_END_OF_STREAM_CHECKImplemented (since 4.4.0)

Related Guidelines

...

Bibliography


...

Image Added Image Added Image Added

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] Class {{InputStream}}
\[[JLS 05|AA. Java References#JLS 05]\] 4.2 Primitive Types and Values
\[[Pugh 08|AA. Java References#Pugh 08]\] "Waiting for the end"

INT34-J. Perform explicit range checking to ensure integer operations do not overflow      06. Integers (INT)      INT36-J. Use shift operators correctly