开发者

Is there any Java Decompiler that can correctly decompile calls to overloaded methods? [closed]

开发者 https://www.devze.com 2022-12-30 22:54 出处:网络
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.

We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.

Closed 4 years ago.

Improve this question 开发者_开发技巧

Consider this (IMHO simple) example:

public class DecompilerTest {
    public static void main(String[] args) {
        Object s1 = "The", s2 = "answer";
        doPrint((Object) "You should know:");
        for (int i = 0; i < 2; i++) {
            doPrint(s1);
            doPrint(s2);
            s1 = "is";
            s2 = new Integer(42);
        }
        System.out.println();
    }

    private static void doPrint(String s1) {
        System.out.print("Wrong!");
    }

    private static void doPrint(Object s1) {
        System.out.print(s1 + " ");
    }
}

Compile it with source/target level 1.1 without debug information (i.e. no local variable information should be present) and try to decompile it. I tried Jad, JD-GUI and Fernflower, and all of them got at least one of the call wrong (i. e. the program printed "Wrong!" at least once)

Is there really no java decompiler that can infer the right casts so that it will not call the wrong overload?

Edit: Target level 1.1 so that there is none of that Java6-specific fast-validation information present. That might give the decompiler a clue that s1 has been declared as Object and not as String. Decompilers should be able to decompile the code even without this information (not necessarily get the original variable type, but show the same behaviour), especially since lots of obfuscators strip it as well.

What decompilers got wrong:

  • They missed the cast to (Object) in the first call.
  • They inferred the type of s1 to be String, but forgot to add a cast to the call to doPrint (so that the String version is called instead of the Object version).
  • One crappy one (I have not even listed) even infers the type of s2 to be String, causing uncompilable code.

In any case, this code never calls the String overload, but the decompiled code did.


Hallo mihi,

sorry for the late response. I'm copying my answer from http://www.reversed-java.com/fernflower/forum?threadfolder=2_DE

Your problem is actually a well known one. Let's see:

1) Pure bytecode doesn't contain any information about the type of object variables, so in the first pass s1 and s2 are declared as Object.

2) Decompiler is trying hard to assign the best possible type to each variable (= "narrowest type principle" implemented in Fernflower). So s1 and s2 are correctly identified as instances of String.

3) Invocation of doPrint give us a direct link to the correct method
private static void doPrint(Object s1)

4) Everything OK so far, right? Now we have got a String variable s1 passed to a function, which expects an Object. Do we need to cast it? Not as such, you would think, as Object is a super-type of String. And yet we do - because there is another function within the same class with the same name and a different parameter signature. So we need to analyse the whole class to find out, whether a cast is needed or not.

5) Generally speaking, it means we need to analyse ALL referenced classes in ALL libraries including the java runtime. A huge load of work! Indeed, this feature was implemented in some alpha version of Fernflower, but have not made it in the production yet because of performance and memory penalty. Other mentioned decompilers lack this ability by design.

Hope I have clarified things a bit :)


Krakatau correctly handles all overloaded methods, even methods overloaded on primitive types, which most decompilers get wrong. It always casts arguments to the exact type of the called method, so the code may be more cluttered than necessary, but at least it is correct.

Disclosure: I am the author of Krakatau.


The JadClipse Eclipse plugin for decompiling also provides the JODE decompiler, which you may want to try. I use it when Jad gives up.

Also the Dava decompiler uses Soot which - last time i looked - was very ambitious in reconstructing the original Java code. I have not tried with your example, but you may want to have a look. http://www.sable.mcgill.ca/dava/


Procyon should handle overloaded method invocations correctly. Like Krakatau, Procyon initially inserts casts for every method argument that doesn't exactly match the target method. However, most of these will be removed during a later phase of decompilation that identifies and eliminates redundant casts. Procyon will only remove casts on call arguments if it can verify that doing so will not result in the call binding to a different method. For example, if the .class declaring the method cannot be resolved, it won't attempt to remove the casts at all, because it has no way of knowing what overloads might conflict.


Adding to the previous answers: Here's a list of modern decompilers as of March 2015:

  • Procyon
  • CFR
  • JD
  • Fernflower

ALL of them support overloaded methods.

You may test above mention decompilers online, no installation required and make your own educated choice. Java decompilers in the cloud: http://www.javadecompilers.com/

0

精彩评论

暂无评论...
验证码 换一张
取 消