[false negative] DoubleCheckedLocking: not reported when the outer null check is written as !(x != null)
- Dominant language
- Java
- Stars
- 7.2k
- Forks
- 820
- Avg merge
- 5h 9m
- Merged PRs (30d)
- 50
Description
**Versions:** Error Prone `error_prone_core` 2.41.0, JDK 25, invoked via `javac` (CLI).
**Description**
`DoubleCheckedLocking` matches the guard by its syntactic form. Rewriting the outer null check from `baz == null` to the logically-equivalent `!(baz != null)` makes the check stop firing, even though the double-checked locking on the non-volatile field — and its unsafe publication — is entirely unchanged. The two programs are behaviourally identical.
**Reproducer (reported):**
```java
public class DclSeed {
Object baz;
Object bar() {
if (baz == null) { // reported here (line 5)
synchronized (this) {
if (baz == null) {
baz = new Object();
}
}
}
return baz;
}
}
```
**Reproducer (NOT reported — the only change is the outer guard):**
```java
public class DclVariant {
Object baz;
Object bar() {
if (!(baz != null)) { // equivalent to `baz == null`; no diagnostic
synchronized (this) {
if (baz == null) {
baz = new Object();
}
}
}
return baz;
}
}
```
**How to run (the `-J--add-exports`/`--add-opens` and `-XDcompilePolicy=simple --should-stop=ifError=FLOW` flags are required for Error Prone on a modern JDK; without them the plugin does not run):**
```
javac \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
-XDcompilePolicy=simple --should-stop=ifError=FLOW \
-processorpath error_prone_core-2.41.0-with-dependencies.jar -Xplugin:ErrorProne \
-d out DclSeed.java
# DclSeed.java:5: warning: [DoubleCheckedLocking] Double-checked locking on non-volatile fields is unsafe
# (running the same command on DclVariant.java produces no DoubleCheckedLocking diagnostic)
```
**Expected:** Error Prone should emit `[DoubleCheckedLocking]` on `DclVariant.java` line 5, but does not.
Contributor guide
Research direction
Start with the DclSeed.java and DclVariant.java reproducers and compare how the outer null guards are recognized. Run the supplied javac/Error Prone command, confirming the diagnostic on DclSeed.java and the missing diagnostic on DclVariant.java. Done means the equivalent `!(baz != null)` guard also emits DoubleCheckedLocking on line 5.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- compilers, devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100