Sonar-java NPE scanning initialize with synchronized(getClass()) in non-final class

I’m seeing a NullPointerException in the sonar-java plugin when scanning a non-final class that violates the synchronizing on getClass() in a non-final class rule (https://rules.sonarsource.com/java/tag/multi-threading/RSPEC-3067). The synchronized(getClass()) call is in an initializer. The reason appears to be the scanner is tracing up from the offensive code, it only considered that it would be in a constructor or other method, so it traced up the expression tree via parent() calls until it hit null.

  • Versions
  • Sonar-Java scanner 5.13.1.18282
  • SonarQube server 7.9 (on RHEL).
  • building with sonar-gradle-plugin 2.7.1 (probably not relevant)
  • Error Observed
Caused by: java.lang.NullPointerException
        at org.sonar.java.checks.synchronization.SynchronizationOnGetClassCheck.isEnclosingClassFinal(SynchronizationOnGetClassCheck.java:68)
        at org.sonar.java.checks.synchronization.SynchronizationOnGetClassCheck.visitNode(SynchronizationOnGetClassCheck.java:59)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.lambda$visit$7(VisitorsBridge.java:295)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:298)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visitChildren(VisitorsBridge.java:280)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:302)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visitChildren(VisitorsBridge.java:280)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:302)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visitChildren(VisitorsBridge.java:280)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:302)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.run(VisitorsBridge.java:271)
        at org.sonar.java.model.VisitorsBridge.visitFile(VisitorsBridge.java:141)
        at org.sonar.java.ast.JavaAstScanner.simpleScan(JavaAstScanner.java:90)
        ... 117 more
  • Steps to Reproduce

This was reproduced inside a rather huge gradle build project with many subprojects. But simplified, it appears only to be a basic static analysis for the following class.

package bugcode;

public class GetClassInNonFinalClassInInitializerKillsSonarJava {
	private static boolean flag;
	{
		synchronized (getClass()) {
			if (!flag) {
				flag = true;
			}
		}
	}
}
  • Potential Workaround

Other than just skipping the offending class, I’ve been able to patch the problem in the sonar-scanner source code, rebuild, and replace the sonar-java plugin jar file to get the proper reporting for the rule violation. I’m not confident that my code is correct. Essentially, I modify org.sonar.java.checks.synchronization.SynchronizationOnGetClassCheck$isEnclosingClassFinal

On line 63, I add INITIALIZER to the while loop:

while (!parent.is(METHOD, CONSTRUCTOR, INITIALIZER)) {

But after the while loop, the parent isn’t going to be a MethodTree, so the early return fails in the cast. I could check if the class was final by modifying that early return to be:

      if (parent instanceof MethodTree) {
        return ((MethodTree) parent).symbol().owner().isFinal();
      } else {
        // hypothesis: the parent is type class for initializers
        return ((ClassTree) parent.parent()).symbol().isFinal();
      }

hello @hajush,

thanks a lot for reporting this issue and for minimal reproducer. I created a ticket to handle this https://jira.sonarsource.com/browse/SONARJAVA-3162

Thank you Tibor!