Issue with bytecode emitted by Kotlin compiler


#1

Hi,

I’m facing an issue with MapDB, a library built with Kotlin, and the fundamental issue seems to be within Kotlin itself.
When analyzing code that uses this bytecode, SonarQube complains that the bytecode is invalid (worse, it actually crashes the analyzer).
Analyzer says “bridge method not marked as synthetic in class XXX”.
From what I can tell, the relevant logic in the Kotlin compiler is in this single line from FunctionCodegen.java :
int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO.

(Notice the trailing “TODO” marker :smile:)

So, should all bridge methods be marked as synthetic?
Maybe not, but is it possible that some bridge methods are currently not but should be marked as synthetic?
Is SonarQube wrong?
I found 2 similar issues with other systems that emit JVM bytecode (namely AspectJ and Groovy) and in both cases they were wrong and were fixed.

Thanks for your help,
Hugues


#2

Looks like these methods indeed should not be both ACC_BRIDGE and ACC_SYNTHETIC, I’ve opened the issue


#3

Hi Denis,
I thought that was the other way around: the affected bridge methods should be flagged as synthetic but are not (at least that’s what the analyzer complaint reads).
Example of decompiled code of size() method of org.mapdb.BTreeMap:

  public final int size();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_FINAL, ACC_BRIDGE
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokevirtual #710                // Method getSize:()I
         4: ireturn

My understanding is that SonarQube analyzer expects to see ACC_SYNTHETIC here.

Edit: here is the relevant line in SonarQube analyzer:

    if (!BytecodeCompleter.isSynthetic(flags)) {
      Preconditions.checkState((flags & Opcodes.ACC_BRIDGE) == 0, "bridge method not marked as synthetic in class " + className);

Cheers,
Hugues


#4

Nothing in the JVM Spec requires synthetic for bridge methods. Looking at their meaning however all bridge methods are generated and therefore meet the specifications expected by synthetic. Both flags exist mainly for compilers though, not the jvm.


#5

I understand exactly the same, but I think it leaves an ambiguity.
It seems we all agree that “bridge implies synthetic”.
Kotlin compiler seems to interpret this as “ACC_BRIDGE” flag is enough because it implies “synthetic”.
SonarQube analyzer seems to interpret this as “any method flagged ACC_BRIDGE must also be flagged ACC_SYNTHETIC”.
Which one is right?

And bytecode static analyzers maybe?

Edit: changing category to “Language design”, seems more fitting after all.


#6

I also asked the Sonar guys, asking who is right between Kotlin compiler and Sonar analyzer, and more importantly is it a good idea to let the analyzer crash on this… and one Sonar dev tends to agree the analyzer is too strict, and has created an issue in their system to deal with this on their side.


#7

Leaving a comment for anyone who still gets this error and lands on this page: the issue has been fixed in SonarJava 4.5, released yesterday (that’s the “Java” plugin within Sonar/SonarQube).