RES00-G: Release Resources When They Are No Longer Needed
Introduction
The Gosu garbage collector only frees up memory that is no longer in use. It does not release non-memory resources such as open file descriptors and database connections. Output streams can hold on to object references, preventing garbage collection until the stream is closed. Failing to release such resources can result in resource exhaustion attacks, leading to performance issues or system crashes. On Windows systems, attempting to delete open files will fail, further complicating resource management. Resource leaks can also create vulnerabilities to resource exhaustion attacks in your application.
It is important to release resources after they have been used explicitly. Close output streams and other resources promptly to prevent leaks and ensure efficient resource management. This practice contributes to your application's stability, security, and performance.
Non-Compliant Code Example (FileHandle)
This non-compliant code example opens a file and uses it but fails to close the file explicitly:
// Noncompliant Code Example
function processFile(filename : String) {
final var stream = new FileInputStream(filename)
final var bufRead = new BufferedReader(
new InputStreamReader(stream)
)
var line : String = bufRead.readLine()
while (line != null) {
print(line)
line = bufRead.readLine()
}
return
}
Compliant Solution (Using)
This compliant solution uses the Gosu using
statement to release all acquired resources regardless of any exceptions that might occur:
// Compliant Solution
function processFileScott(filename: String) {
var stream = new FileInputStream(filename)
using (var bufRead = new BufferedReader(new InputStreamReader(stream))) {
while (true) {
var line = bufRead.readLine()
if (line == null) break
print(line)
}
}
}
The try
-with-resources construct sends any IOException
to the catch
clause, which is forwarded to an exception handler. This generates exceptions when allocating resources while creating the FileInputStream
or BufferedReader
). Any IOException
thrown during the execution of the while
loop and those generated by closing bufRead
or stream
are included.
Non-Compliant Code Example
The following non-compliant code is a real-world example. The function declares three variables conn
, stmt
, and keys
. The conn variable is used in the try
block, but instead of stmt
and keys
, the programmer defines two new variables: cs
and key
. The finally
block closes conn
, stmt
, and keys
resulting in the resources referenced by cs
being leaked. However, the object referenced by key
is returned by the function and does not need to be closed.
// Noncompliant Code Example
override function sendQuotingData(data : String) : BigDecimal {
var conn: Connection
var stmt: PreparedStatement
var keys: ResultSet
try {
conn = _dataSource.getConnection()
// execute insert SQL statement
var cs = conn.prepareCall("begin insert into policyquote (QuoteData) values (?) returning id into ?; END;")
cs.setString(1, data)
cs.registerOutParameter(2, oracle.jdbc.OracleTypes.NUMBER)
cs.execute()
var key = cs.getBigDecimal(2)
return key
} finally {
if (conn != null) {
conn.close()
}
if (stmt != null) {
stmt.close()
}
if (keys != null) {
keys.close()
}
}
}
Compliant Solution
Rewriting the previous non-compliant example with a statement makes avoiding this type of error easier.
// Compliant Solution
override function sendQuotingData(data: String): BigDecimal {
using (
var conn = _dataSource.getConnection(),
// execute insert SQL statement
var cs = conn.prepareCall("begin insert into policyquote (QuoteData) values (?) returning id into ?; END;")
cs.setString(1, data)
cs.registerOutParameter(2, oracle.jdbc.OracleTypes.NUMBER)
cs.execute()
return cs.getBigDecimal(2)
}
}
Non-Compliant Code Example (SQL Connection)
The problem of resource pool exhaustion is exacerbated in the case of database connections. Many database servers allow only a fixed number of connections, depending on configuration and licensing. Consequently, failure to release database connections can result in the rapid exhaustion of available connections. This non-compliant code example fails to close the connection when an error occurs during the execution of the SQL statement or the processing of the results:
// Noncompliant Code Example
public void getResults(String sqlQuery) {
try {
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sqlQuery);
processResults(rs);
stmt.close(); conn.close();
} catch (SQLException e) { /* Forward to handler */ }
}
Non-Compliant Code Example
In this non-compliant code example, the call to rs.close()
or stmt.close()
might throw a SQLException
, in which case conn.close()
is never called.
// Noncompliant Code Example
try {
var conn = getConnection()
var stmt = conn.createStatement()
var rs = stmt.executeQuery(sqlQuery)
processResults(rs)
}
catch (sqle: SQLException) {
// Forward to handler
}
finally {
rs?.close()
stmt?.close()
conn?.close()
}
Compliant Solution
This compliant solution ensures that resources are released as required:
// Compliant Solution
try {
var conn = getConnection()
var stmt = conn.createStatement()
var rs = stmt.executeQuery(sqlQuery)
processResults(rs);
} catch (SQLException e) {
// Forward to handler
} finally {
try {
rs?.close();
} catch (sqle: SQLException) {
// Forward to handler
} finally {
try {
stmt?.close();
} catch (sqle: SQLException) {
// Forward to handler
} finally {
try {
conn?.close();
} catch (sqle: SQLException) {
// Forward to handler
}
}
}
}
Compliant Solution (Using Statment)
This compliant solution uses the using
statement to ensure that resources are released as required:
// Compliant Solution
using (var conn = getConnection(),
var stmt = conn.createStatement(),
var rs = stmt.executeQuery(sqlQuery)) {
processResults(rs);
} catch (sqle: SQLException) {
// Forward to handler
}
The try
-with-resources construct sends any SQLException
to the catch clause, which is forwarded to an exception handler. Exceptions generated when allocating resources during th creation of the Connection
, Statement
, or ResultSet
, as well as any SQLException
thrown by processResults()
and any SQLException
generated by closing rs
, stmt
, or conn
are included.
Risk Assessment
Failure to explicitly release non-memory system resources when they are no longer needed can result in resource exhaustion.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
RES00-G | Low | Likely | Medium | L4 | L3 |
Additional Resources
Was this page helpful?