False Negative: DoubleCheckedLocking.ql misses non-volatile lazy initialization once the null checks are split across locals, helpers, or early returns.
还没有人认领这个 Issue。
评估
调研方向
从 Likely Bugs/Concurrency/DoubleCheckedLocking.ql 开始,并将其匹配逻辑与 PosCase1_Var2.java、PosCase1_Var3.java、PosCase1_Var5.java、PosCase2_Var3.java 和 PosCase2_Var5.java 进行比较。跟踪查询如何对非 volatile 读取、同步初始化、局部变量、辅助函数和提前返回进行建模。完成的标准是 checker 报告全部五种不安全模式,且不依赖某一种规范 AST 形状。
由索引模型根据 Issue 内容生成。
描述
False Negative: DoubleCheckedLocking.ql misses non-volatile lazy initialization once the null checks are split across locals, helpers, or early returns.
Version
codeql 2.24.3
Checker
- Checker id:
Likely Bugs/Concurrency/DoubleCheckedLocking.ql - Checker description: Detects double-checked locking patterns on non-volatile fields that are not thread-safe due to improper synchronization and field visibility issues.
Description of the false negative
All five samples preserve the same unsafe publication pattern: a non-volatile field is read outside synchronization and lazily initialized under synchronization. The code only changes how the null checks and the return are spelled.
That should still be enough for Likely Bugs/Concurrency/DoubleCheckedLocking.ql to report the pattern.
Affected test cases
PosCase1_Var2.java
The boolean temporaries only cache the same two null checks. This is still ordinary double-checked locking on a non-volatile field.
// Double-checked locking on non-volatile, non-immutable field should be flagged as thread-unsafe.
package scensct.var.pos;
public class PosCase1_Var2 {
private Object instance;
public Object getInstance() {
// outer check with boolean flag
boolean needSync = instance == null;
if (needSync) {
synchronized (this) {
// inner check with explicit condition variable
boolean stillNull = instance == null;
if (stillNull) {
instance = new Object();
}
}
}
return instance;
}
}
PosCase1_Var3.java
The early return does not make the pattern safe. The field is still observed outside synchronization and initialized lazily inside the synchronized block.
// Double-checked locking on non-volatile, non-immutable field should be flagged as thread-unsafe.
package scensct.var.pos;
public class PosCase1_Var3 {
private Object instance;
public Object getInstance() {
if (instance != null) {
return instance; // early return instead of if-null
}
synchronized (this) {
if (instance == null) {
instance = new Object();
}
return instance; // return inside synchronized block
}
}
}
PosCase1_Var5.java
Moving the inner null check into initSingleton() only hides the same unsafe initialization pattern behind a helper.
// Double-checked locking on non-volatile, non-immutable field should be flagged as thread-unsafe.
package scensct.var.pos;
public class PosCase1_Var5 {
private Object instance;
private void initSingleton() {
if (instance == null) {
instance = new Object();
}
}
public Object getInstance() {
if (instance == null) {
synchronized (this) {
// inner check moved into helper but still inside sync
initSingleton();
}
}
return instance;
}
}
PosCase2_Var3.java
The helper methods separate the outer check, the synchronized initialization, and the final read, but the field is still accessed outside synchronization and remains non-volatile.
// Double-checked locking on non-volatile immutable-type field with field access outside synchronized block should be flagged.
package scensct.var.pos;
public class PosCase2_Var3 {
private String instance;
public String getInstance() {
if (isNotInitialized()) { // Outer check extracted to helper
initializeSafely();
}
return retrieveInstance(); // Access extracted to helper
}
private boolean isNotInitialized() {
return instance == null;
}
private void initializeSafely() {
synchronized (this) {
if (instance == null) {
instance = "lazy";
}
}
}
private String retrieveInstance() {
return instance; // Access outside synchronized block
}
}
PosCase2_Var5.java
This is still a read-outside-sync / initialize-inside-sync pattern. Restructuring it as an early return does not repair the memory-visibility problem.
// Double-checked locking on non-volatile immutable-type field with field access outside synchronized block should be flagged.
package scensct.var.pos;
public class PosCase2_Var5 {
private String instance;
public String getInstance() {
// Restructured control flow with early return for null after sync
if (instance != null) {
return instance; // Early return, but still access outside sync
}
synchronized (this) {
if (instance == null) {
instance = "done";
}
}
// Field accessed after synchronization block
return instance;
}
}
Cause analysis
The query appears too tied to one canonical AST shape for double-checked locking. As soon as the outer check is cached in a local, the inner initialization moves to a helper, or the method returns early on the fast path, the match falls apart.
That is a real modeling gap. The thread-safety problem depends on non-volatile publication and unsynchronized reads, not on whether the code is written in one exact syntactic form.
References
None known.
- 主要语言
- CodeQL
- 星标
- 10.1k
- 派生
- 2.1k
- 平均合并
- 2 天 16 小时
- 30 天内合并 PR
- 143
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
github/codeql 的其他 Issue
-
agentic-workflows
难度 2/5 1-3 小时 新手友好度 70/100
-
false-positive javascript
难度 2/5 1-3 小时 新手友好度 84/100
-
难度 2/5 1-3 小时 新手友好度 82/100
-
难度 2/5 1-3 小时 新手友好度 78/100
-
false-positive
难度 2/5 1-3 小时 新手友好度 70/100
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
punkpeye/mcp-remote#369 ·
-
Mend: dependency security vulnerability untriaged
难度 1/5 1 小时以内 新手友好度 86/100
-
难度 2/5 1-3 小时 新手友好度 68/100
-
bug
难度 1/5 1 小时以内 新手友好度 90/100
cisagov/vulnrichment#337 ·
-
bug DUP Reservations
难度 2/5 1-3 小时 新手友好度 68/100
bcgov/reserve-rec-public#896 ·