Skip to content

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

Description

@MarkLee131

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):

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):

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions