Storyyeller / Krakatau

Java decompiler, assembler, and disassembler
GNU General Public License v3.0
1.97k stars 220 forks source link

Wrong type inference #63

Closed samczsun closed 8 years ago

samczsun commented 8 years ago

Here is some handwritten bytecode

.version 52 0 
.class public super proof 
.super java/lang/Object 

.method public <init> : ()V 
    .code stack 1 locals 1 
L0:     aload_0 
L1:     invokespecial Method java/lang/Object <init> ()V 
L4:     return 
L5:     
        .linenumbertable 
            L0 5 
        .end linenumbertable 
        .localvariabletable 
            0 is this Lproof; from L0 to L5 
        .end localvariabletable 
    .end code 
.end method 

.method public static main : ([Ljava/lang/String;)V 
    .code stack 10 locals 10
L0:     new java/lang/Integer 
        iconst_0
        ldc 6
        invokestatic Method java/lang/Math min (II)I
        ifeq L9
        dup
        ldc 2
        invokespecial Method java/lang/Integer <init> (I)V
        checkcast java/lang/System
        return
        .stack full
            locals
            stack Uninitialized L0
        .end stack
L9:     dup
ldc 5
L4:     invokespecial Method java/lang/Integer <init> (I)V 
L7:     astore_1 
L8:     getstatic Field java/lang/System out Ljava/io/PrintStream; 
L11:    aload_1 
L12:    invokevirtual Method java/lang/Object toString ()Ljava/lang/String; 
L15:    invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V 
L18:    return 
L19:    
        .linenumbertable 
            L0 7 
            L8 8 
            L18 9 
        .end linenumbertable 
        .localvariabletable 
            0 is args [Ljava/lang/String; from L0 to L19 
            1 is o Ljava/lang/Object; from L8 to L19 
        .end localvariabletable 
    .end code 
.end method 
.sourcefile 'proof.java' 
.end class 

Upon compiling and running it should print 5

Here is what Krakatau disassembles it to

public class proof {
    public proof()
    {
        super();
    }

    public static void main(String[] a)
    {
        System a0 = null;
        if (Math.min(0, 6) == 0)
        {
            a0 = new System(5);
            java.io.PrintStream a1 = System.out;
            Integer a2 = (Integer)(Object)a0;
            a1.println(((Object)a2).toString());
            return;
        }
        a0 = new System(2);
        a0 = (System)a0;
    }
}

The fake checkcast after the 'opaque' predicate appears to cause Krakatau to falsely infer the type of the Object

Storyyeller commented 8 years ago

That's definitely not supposed to happen. I'll have to take a look later. Thanks for the report.

Storyyeller commented 8 years ago

I added a temporary workaround to fix the issue. A proper solution would require a deeper redesign.