Skip to main content

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.

RuleSeverityLikelihoodRemediation CostPriorityLevel
RES00-GLowLikelyMediumL4L3

Additional Resources