Decompilation SATest

Program-Transformation.Org: The Program Transformation Wiki

Source Again Java Decompiler Tests

Ahpah kindly provided a copy of Source Again Professional version 1.10j (a commercial decompiler). Earlier tests were based on the demonstration decompiler available at this website.

Fibo

For source code see DecompilerFiboTestSource. Decompiled output:
// 
// SourceAgain (TM) Professional v1.10j (C) 2003 Ahpah Software Inc
// 

import java.io.PrintStream;

class Fibo {

    private static int fib(int int1)
    {
        if( int1 > 1 )
            return fib( int1 - 1 ) + fib( int1 - 2 );
        else
            return int1;
    }

    public static void main(String[] String_1darray1)
        throws Exception
    {
        int int2 = 0;
        int int3;

        try
        {
            int2 = Integer.parseInt( String_1darray1[0] );
        }
        catch( Exception Exception4 )
        {
            System.out.println( "Input error" );
            System.exit( 1 );
        }
        int3 = fib( int2 );
        System.out.println( "fibonacci(" + int2 + ") = " + int3 );
    }
}
The output compiled correctly with no modifications.

Casting

For source code see DecompilerCastingTestSource. Here is the output from Source Again:

//
// SourceAgain (TM) Professional v1.10j (C) 2003 Ahpah Software Inc
//

import java.io.PrintStream;

public class Casting {

    public static void main(String[] String_1darray1)
    {
        char char2;

        for( char2 = (char) 0; char2 < 128; char2 = (char) (char2 + 1) )
            System.out.println( "ascii " + char2 + " character " + char2 );
    }
}

This is pretty and compact, but the cast is missing. The non professional version (as for example available on the web) gives variable names that are to my mind prettier (e.g. "c" vs "char2"), but both versions are incorrect.

Inner classes

For source code, see DecompilerInnerClassesTestSource. When decompiled with Source Again, the result is:

//
// SourceAgain (TM) Professional v1.10j (C) 2003 Ahpah Software Inc
//

import java.io.PrintStream;

public class Usa {

    public class England {

        public class Ireland {

            public String name = "Dublin";

            public void print_names()
            {
                System.out.println( name );
            }
        }

        public String name = "London";
    }

    public String name = "Detroit";
}

The inner classes are reproduced perfectly. This is an area where the professional version differs markedly from the non professional version; in the latter, the inner classes are completely missing.

Deuces Wild

This is a 38K applet with two dimensional arrays of integers, some floating point code, and so on. The output from this decompiler is very readable. However, there were a few compile errors, all associated with defining the variable i more than once. In a few cases, this was moderately serious, because it was not clear which version of i some references were referring to. When these errors were corrected, the application compiled without warning or error. It displayed the initial screen correctly, but the cards did not turn over, and none of the buttons appeared to do anything.

Sable Test Program

For source code, see DecompilerSableTestSource. Here is the result for function f (as produced by Source Again):

// 
// SourceAgain (TM) Professional v1.10j (C) 2003 Ahpah Software Inc
//

public class Main {

    public static void f(short short1)
    {
        Object Object4;
        boolean boolean5;

        if( short1 > 10 )
        {
            Object Object3 = new Rectangle( short1, short1 );

            boolean5 = ((Rectangle) Object3).isFat();
            Object4 = Object3;
        }
        else
        {
            Object Object2 = new Circle( short1 );

            boolean5 = ((Circle) Object2).isFat();
            Object4 = Object2;
        }
        if( !boolean5 )
            ((Drawable) Object4).draw();
    }

    public static void main(String[] String_1darray1)
    {
        f( (short) 11 );
    }
}
Source Again has ignored the class hierarchy; obj is of type Object . It is correctly cast as needed; the program compiles without error.

Optimised bytecode

For source code, see DecompilerOptimisedTestSource. This was the result from Source Again for the method f:

// 
// SourceAgain (TM) Professional v1.10j (C) 2003 Ahpah
//

public class Main {

    public static void f(short short1)
    {
        Object Object2;
        boolean boolean3;

        if( short1 > 10 )
        {
            Object2 = new Rectangle;
            (Rectangle) Object2( short1, short1 );
            boolean3 = ((Rectangle) Object2).isFat();
            Object2 = Object2;
        }
        else
        {
            Object2 = new Circle;
            (Circle) Object2( boolean3 );
            boolean3 = ((Circle) Object2).isFat();
            Object2 = Object2;
        }
        if( !boolean3 )
            ((Drawable) Object2).draw();
    }

    public static void main(String[] String_1darray1)
    {
        f( (short) 11 );
    }
}

In addition, the call to new and the constructor for both the Rectangle and the Circle object are separated. Strangely, all decompilers except Dava have had this problem. Also, the parameter to the constructor for Circle should be short1, not boolean3.

Simple control flow

For source code, see DecompilerControlFlowTestSource. Source Again produces:

    public int foo(int int1, int int2)
    {
        while( int1 < int2 )
            int1 = int2++ / int1;
        return int2;
    }
This is certainly wrong, because there is no exception handling code, and a divide by zero error is clearly possible.

Exceptions

For source code, see DecompilerExceptionTestSource. Here is Source Again's output:

    public void foo()
    {
        System.out.println( "a" );
label_15:
        {
            try
            {
                System.out.println( "b" );
                try
                {
                    System.out.println( "c" );
                    break label_15;
                }
                catch( Exception Exception1 )
                {
                    System.out.println( "e" );
                }
            }
            catch( RuntimeException RuntimeException2 )
            {
                System.out.println( "g" );
            }
            System.out.println( "f" );
            return;
        }
        System.out.println( "d" );
    }

While this is close to correct, block d is not protected (if an Exception occurs in block d, the code in e is supposed to be executed).

Life

The professional version of Source Again did a very creditable job. There were irritating errors, mainly to do with constructors again. For example, here is a change I had to make:

        /*
        (Coord_Pair4 = (Coord_Pair) new Coord_Pair).X = From.X;
        (Coord_Pair4 = (Coord_Pair) new Coord_Pair).Y = From.Y;
        return Coord_Pair4 = (Coord_Pair) new Coord_Pair;
        */
        Coord_Pair4 = new Coord_Pair();
        Coord_Pair4.X = From.X;
        Coord_Pair4.Y = From.Y;
        return Coord_Pair4;

I have not had time to finish this test, but it feels to me that Source Again professional comes the closest to being able to decompile this program.

CategoryDecompilation