是否有任何Java Decompiler可以正确反编译对重载方法的调用?

mih*_*ihi 8 java jad decompiler

考虑这个(恕我直言)简单的例子:

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 + " ");
    }
}
Run Code Online (Sandbox Code Playgroud)

在没有调试信息的情况下用源/目标级别1.1编译它(即不应存在局部变量信息)并尝试对其进行反编译.我尝试过Jad,JD-GUI和Fernflower,他们都至少有一个错误的调用(即程序打印"错误!"至少一次)

真的没有java反编译器可以推断出正确的强制转换,以便它不会调用错误的重载吗?

编辑:目标级别1.1,以便不存在特定于Java6的快速验证信息.这可能会给反编译器一个线索,即s1已被声明为Object而不是String.即使没有这些信息,反编译器也应该能够反编译代码(不一定得到原始变量类型,但显示相同的行为),特别是因为许多混淆器也将它剥离.

反编译器出了什么问题:

  • 他们(Object)在第一次通话中错过了演员.
  • 他们推断的类型s1String,却忘了铸造添加到调用doPrint(使带子版本叫做替代对象版本).
  • 一个糟糕的(我甚s2至没有列出)甚至推断出类型为String,导致无法编译的代码.

在任何情况下,此代码从不调用String重载,但反编译的代码确实如此.

Sti*_*ver 9

你好mihi,

回复晚了非常抱歉.我正在复制我的回答http://www.reversed-java.com/fernflower/forum?threadfolder=2_DE

你的问题实际上是一个众所周知的问题.让我们来看看:

1)纯字节码不包含任何有关对象变量类型的信息,因此在第一次传递时,s1和s2被声明为Object.

2)反编译器正在努力为每个变量分配最佳类型(=在Fernflower中实现的"最窄类型原则").所以s1和s2被正确识别为String的实例.

3)调用doPrint给我们直接链接到正确的方法
private static void doPrint(Object s1)

4)到目前为止一切都好,对吗?现在我们有一个String变量s1传递给一个函数,它需要一个Object.我们需要施展吗?你不会这么认为,因为Object是一个超类型的String.然而我们这样做 - 因为在同一个类中有另一个具有相同名称和不同参数签名的函数.因此,我们需要分析整个班级,以了解是否需要演员阵容.

5)一般来说,这意味着我们需要分析所有库中的所有引用类,包括java运行时.大量的工作!实际上,这个功能是在Fernflower的某些alpha版本中实现的,但由于性能和内存损失而尚未在生产中实现.其他提到的反编译器在设计上缺乏这种能力.

希望我有点澄清一点:)

  • "纯字节码不包含任何有关对象变量类型的信息" - 错误.类型派生自类型化数据源(参数,字段)以及操作和方法调用(所有类型都是键入的).堆栈映射属性也提供给方法代码.此外,字节码验证程序可以防止使用错误键入的局部变量加载类文件. (3认同)

Ant*_*ony 5

Krakatau正确处理所有重载方法,甚至是在原始类型上重载的方法,大多数反编译器都会出错。它总是将参数强制转换为被调用方法的确切类型,因此代码可能比必要的更混乱,但至少它是正确的。

披露:我是 Krakatau 的作者。