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 . It will return -1 only when the end of the input stream has been reached. The similar (0x00-0xff). The 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 (0x0000-0xffff). Both methods return the 32-bit value -1 (0xffffffff) to indicate that the end of the stream has been reached . Both methods 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 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 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 rule 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 −1 in an attempt to detect the end of the 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 (because the char type is unsigned and the value of c is 0-extended to 0x0000FFFF).

Code Block
bgColor#FFcccc

FileInputStream in;
// initializeInitialize stream 
byte data;
while ((data = (byte) in.read()) != -1) { 
  // ... 
}

When If the return value of read() method is cast to the byte value 0xFF, the returned byte value is encounters a 0xFF byte in the file, this value becomes indistinguishable from the -1 −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−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−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;
// initializeInitialize 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 the value of type int returned by the read() method directly to a value of type char, which is then compared with -1 −1 in an attempt to detect the end of stream. This conversion leaves the value of c data as 0xFFFF (e.g., Character.MAX_VALUE) instead of -1−1. Consequently, the test for the end of stream file never evaluates to true.

Code Block
bgColor#FFcccc

FileReader in;
// initializeInitialize stream 
char cdata;
while ((cdata = (char) in.read()) != -1) { 
  // ... 
}

Compliant Solution (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−1, it can be safely cast to type char.

Code Block
bgColor#ccccff

FileReader in;
// initializeInitialize stream 
int inbuff;
char data;
while ((inbuff = in.read()) != -1) { 
  data = (char) inbuff;
  // ...  
}

Risk Assessment

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

High

probable

Probable

medium

Medium

P12

L1

Automated Detection

Some static analysis tools can detect violations of this rule.

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

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="d2927216-b657-4720-9f9d-880b5307f5be"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

Class InputStream

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4dfeee2a-016c-473a-82f5-f5ab72c7d282"><ac:plain-text-body><![CDATA[

[[JLS 2005

AA. Bibliography#JLS 05]]

[§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="d57936cd-66b1-4afe-9c62-7588003aab66"><ac:plain-text-body><![CDATA[

[[Pugh 2008

AA. Bibliography#Pugh 08]]

Waiting for the End

]]></ac:plain-text-body></ac:structured-macro>

Bibliography


...

Image Added Image Added Image Removed      12. Input Output (FIO)      Image Modified