google / google/error-prone

[false negative] DoubleCheckedLocking: not reported when the outer null check is written as !(x != null)

Open
#5,963 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.