Product/version: SonarQube Community Build 26.7.0.124771, sonar-scanner 8.1.0.6389
Language: Java
Rule: java:S2168
Issue:
S2168 reports the double-checked locking on the non-volatile field helper in seed/Dcl.java. In variant/Dcl.java the outer null check is written !(helper != null) instead of helper == null, everything else is the same, and nothing is reported. !(!(helper == null)) isn’t reported either.
DoubleCheckedLockingCheck.isIfFieldEqNull only treats an if as a field null check when the condition is EQUAL_TO with a null literal on one side (DoubleCheckedLockingCheck.java:88-103 at 8.34.0.44906, unchanged at 88.0.0.3367). It never unwraps !, so the outer if isn’t pushed on the field stack and the inner check finds no matching outer one.
PMD’s DoubleCheckedLocking had the same gap and now accepts negated null checks (pmd#6900, fixed in 7.27.0). Error Prone accepted the same report (error-prone#5963).
Reproducer:
seed/Dcl.java:
public class Dcl {
private Helper helper;
Helper getHelper() {
if (helper == null) { // S2168 reported on the synchronized below
synchronized (this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
static class Helper {
int x;
}
}
variant/Dcl.java:
public class Dcl {
private Helper helper;
Helper getHelper() {
if (!(helper != null)) { // the same outer check; nothing reported
synchronized (this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
static class Helper {
int x;
}
}
Expected behavior:
S2168 (“Remove this dangerous instance of double-checked locking.”) on the synchronized keyword in variant/Dcl.java, as in seed/Dcl.java.
How to reproduce:
# one project per file
sonar-scanner -Dsonar.projectKey=<key> -Dsonar.sources=. \
-Dsonar.java.binaries=. -Dsonar.scm.disabled=true
Output of the commands above:
### SonarQube Community Build 26.9.0.129388 (sonar-java 8.41.0.47177), server reports 26.9.0.129388, default Sonar way profile rule: S2168
--- SEED -- expected: reported (seed/)
java:S1220 line - Move this file to a named package.
java:S2168 line 6 Remove this dangerous instance of double-checked locking. <== S2168
[S2168: 1]
--- VARIANT -- expected: reported; actual: not reported (variant/)
java:S1220 line - Move this file to a named package.
java:S1940 line 5 Use the opposite operator ("==") instead.
[S2168: 0]