github / github/codeql

False Negative: CloseSql.ql misses leaked JDBC resources once the allocation site is split across helper calls or `getResultSet()`.

未关闭
#21,531 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
question
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。