This is an issue when the return value of read operations from file or stream input classes is cast to a narrower data type (such as a single byte
or character type) before being compared to -1 to detect end-of-stream.
Stream reading methods in many languages return a wider integer type that can represent all possible data values (typically 0-255 for byte-oriented streams) plus a special sentinel value (typically -1) to indicate end-of-stream. This design allows distinguishing between all valid data values and the end-of-stream condition.
When you cast the return value to the narrower data type (such as a signed byte or character type) before checking for the sentinel value, you introduce a critical bug due to type narrowing:
This causes two types of failures:
The same issue applies to character-based streams where certain character values can be misinterpreted as end-of-stream.
This pattern is always a latent bug even if the current data does not contain 0xFF, because input sources can change and any byte stream may eventually carry that value.
In Java, this applies specifically to the read() method in InputStream and Reader classes.
This bug can lead to data corruption when input sources are read incompletely, or to infinite loops when termination conditions are never detected. In data processing applications, this can cause silent data loss that is difficult to diagnose. In server applications, it may lead to resource exhaustion or application hangs.
Store the return value of read() in an int variable first. Check if it equals -1 to detect end-of-stream.
Only after confirming it’s not -1 should you cast it to byte or char for processing.
FileInputStream fis = new FileInputStream("data.bin");
byte b;
while ((b = (byte) fis.read()) != -1) { // Noncompliant
process(b);
}
FileInputStream fis = new FileInputStream("data.bin");
int data;
while ((data = fis.read()) != -1) {
byte b = (byte) data;
process(b);
}