Decompilation Jad Test
Program-Transformation.Org: The Program Transformation Wiki
Jad Java Decompiler Simple Tests
This page performs some tests on JAD version 1.5.8e. Output has been trimmed slightly for ease of comparison to the original source.
Fibo
For source, see
DecompilerFiboTestSource. Decompiled output from Jad:
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
import java.io.PrintStream;
class Fibo
{
Fibo()
{
}
private static int fib(int i)
{
if(i > 1)
return fib(i - 1) + fib(i - 2);
else
return i;
}
public static void main(String args[])
throws Exception
{
int i = 0;
try
{
i = Integer.parseInt(args[0]);
}
catch(Exception exception)
{
System.out.println("Input error");
System.exit(1);
}
int j = fib(i);
System.out.println("fibonacci(" + i + ") = " + j);
}
}
As you can see, the decompilation is almost identical to the source.
Casting
For source, see
DecompilerCastingTestSource. Here is the output from Jad:
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
import java.io.PrintStream;
public class Casting
{
public Casting()
{
}
public static void main(String args[])
{
for(char c = '\0'; c < 128; c++)
System.out.println("ascii " + (int)c + " character " + c);
}
}
As you can see, it's readable, similar to the original, and is correct. No modifications were needed to recompile it.
Inner classes
For source, see
DecompilerInnerClassesTestSource. When decompiled with Jad, the result is
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
import java.io.PrintStream;
public class Usa
{
public class England
{
public class Ireland
{
public void print_names()
{
System.out.println(name);
}
public String name;
public Ireland()
{
name = "Dublin";
}
}
public String name;
public England()
{
name = "London";
}
}
public Usa()
{
name = "Detroit";
}
public String name;
}
I'm no inner classes expert, but this looks right to me, even though it looks different to the original source code.
Deuces Wild
This is a 38K applet with two dimensional arrays of integers, some floating point code, and so on. It decompiled in about 0.8 seconds, with no errors, and recompiled and ran perfectly with no modifications. The data members appear at the end of the class definition, which I find a little irritating. The arrays of strings are initialised fairly naturally, e.g.
String cardrank[] = {
"Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
"Ten", "Jack",
"Queen", "King", "Ace"
};
String cardsuit[] = {
"clubs", "diamonds", "hearts", "spades"
};
However, the string before this one also had ten strings on one line, producing a line that had well over a hundred columns. This is a very minor issue.
Sable Test Program
For source, see
DecompilerSableTestSource. Here is the result for function
f
(as produced by Jad):
public static void f(short word0)
{
Object obj;
boolean flag;
if(word0 > 10)
{
Rectangle rectangle = new Rectangle(word0, word0);
flag = rectangle.isFat();
obj = rectangle;
} else
{
Circle circle = new Circle(word0);
flag = circle.isFat();
obj = circle;
}
if(!flag)
((Drawable) (obj)).draw();
}
It decided to type the reference that was
d
in the original source as type
Object
(name
obj
). This is not ideal, since it requires a cast when used. The cast was at least correctly inserted. Other decompilers such as Jode and Dava can correctly type the "
d
" variable as type
Drawable
. It produced correct code which compiled without modification.
Optimised code
For source, see
DecompilerOptimisedTestSource. This was the result from Jad for the method
f
:
public static void f(short word0)
{
Object obj;
if(word0 > 10)
{
obj = JVM INSTR new #37 <Class Rectangle>;
((Rectangle) (obj)).Rectangle(word0, word0);
word0 = ((Rectangle) (obj)).isFat();
obj = obj;
} else
{
obj = JVM INSTR new #15 <Class Circle>;
((Circle) (obj)).Circle(word0);
word0 = ((Circle) (obj)).isFat();
obj = obj;
}
if(word0 == 0)
((Drawable) (obj)).draw();
}
As you can see, it is confused with the two constructors. The fix is moderately obvious; there is no chance that the error will slip by the java compiler, at least.
Simple control flow
For source, see
DecompilerControlFlowTestSource. Jad produces:
public int foo(int i, int j)
{
while(true)
try
{
while(i < j)
i = j++ / i;
break MISSING_BLOCK_LABEL_28;
}
catch(RuntimeException runtimeexception)
{
i = 10;
}
return j;
}
This result does not compile, and is missing several statements.
Exceptions
For source, see
DecompilerExceptionTestSource. Here is Jad's output:
public void foo()
{
System.out.println("a");
System.out.println("b");
System.out.println("c");
break MISSING_BLOCK_LABEL_39;
this;
System.out.println("g");
break MISSING_BLOCK_LABEL_59;
System.out.println("d");
break MISSING_BLOCK_LABEL_59;
this;
System.out.println("e");
System.out.println("f");
return;
}
JAD has completely given up on any exception handling. Interestingly, in the paper mentioned above, Jad is reported as having one
try
and
catch
clause. Obviously, this output is nowhere near correct, and will not even compile.
Life
This applet is originally compiled in Ada 95. The applet is at
http://www.appletmagic.com/download/demo/LifeRect.html. When Jad was run on this file, it admitted that it could not completely decompile method
run
. It failed this relatively easy control flow code:
if(false) goto _L2; else goto _L1
_L1:
int I = 1;
_L3:
double d;
...
I++;
if(I > 180) goto _L2; else goto _L3
_L2:
which Jode correctly decompiled as follows:
if (true) {
int I = 1;
do {
double d = ...
I++;
} while (I <= 180);
}
Granted, the
if (true)
is strange, but should not throw a decompiler. Similar problems occured with other classes of this applet.
Conclusion
This is a good decompiler: extremely fast, reasonable output quality. It does have a problem with some optimised code, as shown above, but most of the time it's easy to correct. None of the decompilers I have tested so far (8 in total) has passed all the tests. JODE, Dava, and Jad are the top three.
CategoryDecompilation