An exception can occur in the finally block despite compile-time checking. This can prevent other clean-up statements from being executed.
Noncompliant Code Example
This noncompliant code example uses a finally block that closes the reader object. However, it is incorrectly assumed that the statements occurring in the finally block cannot throw exceptions.
public class Operation {
private static void doOperation(String some_file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(some_file));
// Do operations
} finally {
reader.close();
// ... Other clean-up code ...
}
}
public static void main(String[] args) throws IOException {
String path = "somepath";
doOperation(path);
}
}
Notably, the close() method can throw an IOException which prevents any subsequent clean-up statements from being executed. This is not detected at compile time because the type of exception that close() throws is the same as the type of exceptions that methods read() and write() throw.
Compliant Solution (1) (handle exceptions in finally block)
This compliant solution correctly places the close() statement in a try-catch block. As a result, an IOException can be handled without letting it propagate any further.
public class Operation {
static void doOperation(String some_file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(some_file));
try {
// Do operations
} finally {
try {
// Enclose in try-catch block
reader.close();
} catch (IOException ie) {
// Forward to handler
}
// Other clean-up code
}
}
public static void main(String[] args) throws IOException {
String path = "somepath";
doOperation(path);
}
}
Compliant Solution (2) (dedicated method to handle exceptions)
If there is a frequent need to close a stream without throwing an exception, an alternative solution to wrapping every call to close() in its own try-catch block is to use a closeIgnoringException() method, as shown in this compliant solution.
public class Operation {
static void doOperation(String some_file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(some_file));
try {
// Do operations
} finally {
closeIgnoringException(reader);
// Other clean-up code
}
}
private static void closeIgnoringException(BufferredReader s) {
if (s != null) {
try {
s.close();
} catch (IOException ie) {
// Ignore exception if close fails
}
}
}
public static void main(String[] args) throws IOException {
doOperation("somepath");
}
}
Risk Assessment
Failing to handle an exception in a finally block can lead to unexpected results.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
EXC05- J |
low |
unlikely |
medium |
P2 |
L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[Bloch 2005]] Puzzle 41: Field and Stream
[[Harold 1999]]
[[Chess 2007]] 8.3 Preventing Resource Leaks (Java)
EXC04-J. Do not exit abruptly from a finally block 17. Exceptional Behavior (EXC) EXC06-J. Do not allow exceptions to transmit sensitive information