False Negative: CloseSql.ql misses leaked JDBC resources once the allocation site is split across helper calls or `getResultSet()`.
- 主要语言
- CodeQL
- 星标
- 10.1k
- 派生
- 2.1k
- 平均合并
- 2 天 15 小时
- 30 天内合并 PR
- 141
描述
Version
codeql 2.24.3
## Checker
- Checker id: `Likely Bugs/Resource Leaks/CloseSql.ql`
- Checker description: This checker detects SQL resource objects (Connection, Statement, ResultSet) that are initialized locally and not guaranteed to be closed on method exit.
## Description of the false negative
These cases still leak JDBC resources. One is the simplest possible leaked `Connection`. The other two leak `ResultSet` instances that come from a `Statement` parameter and are never closed before the method returns.
What changes between the samples is only how the resource is obtained: directly, through a helper method, or through `Statement.getResultSet()` after `execute(...)`.
## Affected test cases
### `PosCase1.java`
The method opens a `Connection` and exits without closing it. This should be a baseline match for the rule.
### `PosCase6_Var3.java`
The `ResultSet` comes back from a helper, but it still originates from the passed-in `Statement` and still leaks.
### `PosCase6_Var4.java`
The `ResultSet` is retrieved through `stmt.getResultSet()` after `execute(...)`. That is still a live SQL resource that needs to be closed.
## Reproduction code
### `PosCase1.java`
```java
// Scenario 1: A java.sql.Connection is locally initialized, not assigned, not passed to a local constructor, has no parent, and is not closed.
package scensct.core.pos;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class PosCase1 {
public void test() throws SQLException {
// Locally initialized Connection, assigned to a variable but not closed.
Connection conn = DriverManager.getConnection("jdbc:example:db");
// No close() call before method exit.
}
}
```
### `PosCase6_Var3.java`
```java
// Scenario 6: A java.sql.ResultSet is locally initialized as a child of a non-locally-initialized Statement parameter, used directly, and not closed.
package scensct.var.pos;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PosCase6_Var3 {
public void test(Statement stmt) throws SQLException {
ResultSet rs = fetchResult(stmt);
// rs not closed
}
private ResultSet fetchResult(Statement s) throws SQLException {
return s.executeQuery("SELECT 1");
}
}
```
### `PosCase6_Var4.java`
```java
// Scenario 6: A java.sql.ResultSet is locally initialized as a child of a non-locally-initialized Statement parameter, used directly, and not closed.
package scensct.var.pos;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PosCase6_Var4 {
public void test(Statement stmt) throws SQLException {
boolean hasResults = stmt.execute("SELECT 1");
if (hasResults) {
ResultSet rs = stmt.getResultSet();
// rs not closed
}
}
}
```
## Cause analysis
`Likely Bugs/Resource Leaks/CloseSql.ql` appears to be tied too closely to one acquisition shape. It handles some direct JDBC constructions, but coverage gets weaker once the returned resource is produced through a helper or through a second-stage API like `getResultSet()`.
That leaves a real blind spot. In production JDBC code, `ResultSet` objects are often obtained indirectly rather than from a single inline `executeQuery(...)` call. The leak is still the same: the method owns a SQL resource and does not close it.
贡献指南
调研方向
从 Likely Bugs/Resource Leaks/CloseSql.ql 开始,并将其获取处理与受影响的 PosCase1.java、PosCase6_Var3.java 和 PosCase6_Var4.java 示例进行比较。验证 checker 会报告泄漏的 Connection 以及间接获取的两个 ResultSet 实例,同时保持现有覆盖率。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- java
- 领域
- devtools, security
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 50/100