The Java Development Kit 1.7 (JDK 1.7) introduced the "trythe try-with-resources " statement [JLS 2011] statement (see the JLS, §14.20.3, "try
-with-resources" that makes it much easier to deal with [JLS 2013]), which simplifies correct use of resources that implement the java.lang.AutoCloseable
interface, including those that implement the java.io.Closeable
interface.
Using the try-with-resources statement avoids problems that can arise when closing resources with an ordinary try
-catch
-finally
block, such as failing to close a resource because an exception is thrown as a result of closing another resource, or masking an important exception when a resource is closed.
Use of the try-with-resources statement is also illustrated in in ERR05-J. Do not let checked exceptions escape from a finally block, FIO03-J. Remove temporary files before termination, and FIO04-J. Release resources when they are no longer needed.
Noncompliant Code Example
This noncompliant code example uses an ordinary try
-catch
-finally
block to try in an attempt to close two resources. However, if closing the BufferedReader
br
results in an exception being thrown, then the BufferedWriter
bw
will not be closed.
Code Block | ||
---|---|---|
| ||
public void err54_nce1processFile(String inPath, String outPath) throws IOException{ BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new FileReader(inPath)); bw = new BufferedWriter(new FileWriter(outPath)); // processProcess the input and produce the output } finally { } finallytry { if (br != null) { br.close(); } if (bw != null) { bw.close(); } } catch (IOException x) { // Handle error } } } |
However, if an exception is thrown when the BufferedReader
br
is closed, then the BufferedWriter
bw
will not be closed.
Compliant Solution (finally block)
This compliant solution uses a try-with-resources statement which will guarantee that both br
and bw
are closed, regardless of any exceptions potentially thrown during the close operationssecond finally
block to guarantee that bw
is properly closed even when an exception is thrown while closing br
.
Code Block | ||
---|---|---|
| ||
public void err54_cs1processFile(String inPath, String outPath) throws throws IOException { try (BufferedReader BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new FileReader(inPath)); BufferedWriter bw = new BufferedWriter(new FileWriter(outPath));) { // processProcess the input and produce the output } finally { } } |
Noncompliant Code Example
This noncompliant code example uses an ordinary try-finally block to try to close a resource. However, if there is an exception thrown during the processing of the input and another exception thrown when closing the Bufferedreader
br
, then the exception thrown as a result of processing the input will be lost, and important information about that exceptional circumstance may be missed.
Code Block | ||
---|---|---|
| ||
public void err54_nce2(String inPath) throws IOException{ BufferedReader br = null; if (br != null) { try { br = new BufferedReader(new FileReader(inPath) br.close(); } catch // process the input and produce the output (IOException x) { // Handle error } finally { if (brbw != null) { br try { bw.close(); } catch (IOException x) { // Handle error } } } } } } |
Compliant Solution (try
-with-resources)
This compliant solution uses a try-with-resources statement which will not suppress any exceptions thrown during the processing of the input while still guaranteeing that br
is closed.to manage both br
and bw
.
Code Block | ||
---|---|---|
| ||
public void err54_cs2processFile(String inPath, String outPath) throws throws IOException{ try (BufferedReader br = new BufferedReader(new FileReader(inPath)); BufferedWriter bw = new BufferedWriter(new FileWriter(outPath))) { // processProcess the input and produce the output } catch (IOException ex) { System.err.println("thrown exception: " + ex.toString()); Throwable[] suppressed = ex.getSuppressed(); for (int i = 0; i < suppressed.length; i++) { System.err.println("suppressed exception: " + suppressed[i].toString()); } } } |
This solution preserves any exceptions thrown during the processing of the input while still guaranteeing that both br
and bw
are properly closed, regardless of what exceptions occur. Finally, this code demonstrates how to access every exception that may be produced from the try-with-resources block.
If only one exception is thrown, either during opening, processing, or closing of the filefiles, it the exception will be printed by the after "thrown exception:"
statement. If an exception is thrown during processing, and another one a second exception is thrown while trying to close the either file, then the first exception will be printed after "thrown exception:"
statement will print the exception encountered while closing the file, and the second exception will be printed after "suppressed exception:"
statement will print the exception encountered during processing.
Applicability
Failing to use a try-with-resources statement when dealing correctly handle all failure cases when working with closeable resources may result in some resources not being closed , or in important exceptions being masked, possibly resulting in a denial of service attack.. Note that failure to use a try-with-resources statement cannot be considered a security vulnerability in and of itself because it is possible to write a correctly structured group of nested try
-catch
-finally
blocks guarding the resources that are in use (see ERR05-J. Do not let checked exceptions escape from a finally block). That said, failure to correctly handle such error cases is a common source of vulnerabilities. Use of a try-with-resources statement mitigates this issue by guaranteeing that the resources are managed correctly and that exceptions are never masked.
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.ERR54.CLFIN | Avoid using finally block for closing resource only | ||||||
SonarQube |
| S2093 |
Bibliography
...