Avoid the use of in-band error indicators. These are much less common in Java than in some other programming languages, but they are used in the read(byte[] b, int off, int len)
and read(char[] cbuf, int off, int len)
family of methods in java.io
.
In Java, the best way to indicate an exceptional situation is by throwing an exception, rather than by returning an error code. Exceptions cannot be ignored in the same way that error codes can, and exceptions are propagated across scopes. When using exceptions, the error detection and error handling code is kept separate from the main flow of control. Also, exceptions can be used in situations where error codes cannot be returned (in constructors, for example).
Noncompliant Code Example
...
However, if the input buffer is initially at end-of-file then the read
method will return -1 and the attempt to place the termintor character will throw an ArrayIndexOutOfBoundsException
.
Compliant Solution (Extending)
This compliant solution defines a SafeBufferedReader
class and introduces a readSafe
method that throws an exception if end-of-file is detected.
Code Block | ||
---|---|---|
| ||
class SafeBufferedReader extends BufferedReader { SafeBufferedReader(Reader in) { super(in); } public int readSafe(char[] cbuf, int off, int len) throws EOFException { int read = read(cbuf, off, len); if (read == -1) { throw new EOFException(); } else { return read; } } } // ... SafeBufferedReader safeBuffRdr; try { read = safeBuffRdr.readSafe(chBuff, 0, MAX_READ); chBuff[read] = TERMINATOR; } catch (EOFException eof) { chBuff[0] = TERMINATOR; } |
Compliant Solution (Wrapping)
This compliant solution defines a readSafe
method that wraps the original read
method and throws an exception if end-of-file is detected.
Code Block | ||
---|---|---|
| ||
public static int readSafe(BufferedReader buffer, char[] cbuf, int off, int len) throws EOFException {
int read = buffer.read(cbuf, off, len);
if (read == -1) {
throw new EOFException();
} else {
return read;
}
}
// ...
BufferedReader buffRdr;
// set up buffRdr
try {
read = readSafe(buffRdr, chBuff, 0, MAX_READ);
chBuff[read] = TERMINATOR;
} catch (EOFException eof) {
chBuff[0] = TERMINATOR;
}
|
Risk Assessment
Using in-band error indicators may result in programmers failing to check status codes or using incorrect return values, resulting in undefined behavior.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ERR53-J | low | unlikely probable | high | P1 P2 | L3 |
Automated Detection
Given the comparatively rare occurrence of in-band error indicators in Java, it may be possible to compile a list of all methods that use them and automatically detect their use. However, detecting the safe use of in-band error indicators is not feasible.
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="0a19ea59b0f13988-b373ff1a-43f3458c-b2bb8cf4-633aab067119e16067e16e90"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. References#API 06]] | [Class Reader | http://download.oracle.com/javase/6/docs/api/java/io/Reader.html] | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="60d664fa-d08d-4e05-a497-3949bfde60df"><ac:plain-text-body><![CDATA[ | [[JLS 2011 | AA. References#JLS 11]] | Chapter 11. Exceptions | ]]></ac:plain-text-body></ac:structured-macro> |