Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect decompilation for anonymous class with parameter #50

Closed
nharrand opened this issue Nov 22, 2019 · 4 comments
Closed

Incorrect decompilation for anonymous class with parameter #50

nharrand opened this issue Nov 22, 2019 · 4 comments

Comments

@nharrand
Copy link

Hello,
I might have found a bug where cfr-0.148 decompiles a synthetic field in an anonymous class a bit too literally:

Original java code (from junit4)

    public static Request runner(Runner runner) {
        return new Request(){
            @Overrude
            public Runner getRunner() {
                return runner;
            }
        };
    }

is decompiled (by cfr-0.148) as

    public static Request runner(Runner runner) {
        return new Request(){
            public Runner getRunner() {
                return Runner.this;
            }
        };
    }

When compiling the original sources with javac, the parameter runner is put in a synthetic field in the anonymous class.

Disassembled bytecode of the anonymous class:

  private final org.junit.runner.Runner val$runner;
    descriptor: Lorg/junit/runner/Runner;
    flags: ACC_PRIVATE, ACC_FINAL, ACC_SYNTHETIC

  org.junit.runner.Request$1(org.junit.runner.Runner);
    descriptor: (Lorg/junit/runner/Runner;)V
    flags:
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #10                 // Field val$runner:Lorg/junit/runner/Runner;
         5: aload_0
         6: invokespecial #12                 // Method org/junit/runner/Request."<init>":()V
         9: return
      LineNumberTable:
        line 1: 0
        line 108: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lorg/junit/runner/Request$1;

  public org.junit.runner.Runner getRunner();
    descriptor: ()Lorg/junit/runner/Runner;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #10                 // Field val$runner:Lorg/junit/runner/Runner;
         4: areturn
      LineNumberTable:
        line 111: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lorg/junit/runner/Request$1;

Bytecode beeing decompiled:
Request.zip

@leibnitz27
Copy link
Owner

Oh, that's nice.

The synthetic inner class is actually static, it's supposed to have a static marker, but it doesn't, which is entirely valid.

I wonder what compiler generated that.....

@nharrand
Copy link
Author

Oh, I incorrectly reported that is was compiled with javac, but it was actually compiled with eclipse jdt. (More precisely with maven plugin plexus-compiler-eclipse version 2.8.4)

@leibnitz27
Copy link
Owner

Ah, nice. JDT does all sorts of horrible and weird things (and outputs unsafe code in places).

Still, I really need to compile up my entire test set using JDT - one to add to https://github.com/leibnitz27/cfr_tests/blob/master/pom.xml

@leibnitz27
Copy link
Owner

Oh, I forgot - jdk also does this since java 9. (doesn't mark static anonymous inners as static).
But my test to infer this doesn't kick in until java 9, and this is java <6.

Makes sense. The fix as committed is useful to have anyway!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants