Closed myspringchen closed 4 years ago
Thanks a lot for the detailed report. I am not 100% sure but the problem might be that the exception handler in the bytecode should also include bytecode 19, not just 12 to 18.
Could you maybe do us a favour and disassemble also the respective method of the original Java .class file (first producing such a .class file with javac in case you are using Soot on source code)?
Hi, Eric,
The original code is given as follows. Soot transforms the bytecode into the jimple code, while fails in transforming it back correctly.
Regards, Yuting
The original bytecode is:
private static int getStartLevel();
descriptor: ()I
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=4, locals=1, args_size=0
0: ldc #47 // String osgi.startLevel
2: invokestatic #1465 // Method org/eclipse/osgi/framework/internal/core/FrameworkProperties.getProperty:(Ljava/lang/String;)Ljava/lang/String;
5: astore_0
6: aload_0
7: ifnull 51
10: aload_0
11: invokestatic #1324 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
14: ireturn
15: pop
16: getstatic #1254 // Field debug:Z
19: ifeq 51
22: getstatic #1253 // Field java/lang/System.out:Ljava/io/PrintStream;
25: new #765 // class java/lang/StringBuffer
28: dup
29: ldc_w #704 // String Start level =
32: invokespecial #1346 // Method java/lang/StringBuffer."
The corresponding Jimple code: private static int getStartLevel() { java.lang.String r0, $r6; int $i0; java.lang.NumberFormatException $r1; boolean $z0; java.lang.StringBuffer $r2, $r4, $r5; java.io.PrintStream $r3;
r0 = staticinvoke <org.eclipse.osgi.framework.internal.core.FrameworkProperties: java.lang.String getProperty(java.lang.String)>("osgi.startLevel");
if r0 == null goto label4;
label1:
$i0 = staticinvoke <java.lang.Integer: int parseInt(java.lang.String)>(r0);
label2:
return $i0;
label3:
$r1 := @caughtexception;
$z0 = <org.eclipse.core.runtime.adaptor.EclipseStarter: boolean debug>;
if $z0 == 0 goto label4;
$r3 = <java.lang.System: java.io.PrintStream out>;
$r2 = new java.lang.StringBuffer;
specialinvoke $r2.<java.lang.StringBuffer: void <init>(java.lang.String)>("Start level = ");
$r4 = virtualinvoke $r2.<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>(r0);
$r5 = virtualinvoke $r4.<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>(" parsed. Using hardcoded default: 6");
$r6 = virtualinvoke $r5.<java.lang.StringBuffer: java.lang.String toString()>();
virtualinvoke $r3.<java.io.PrintStream: void println(java.lang.String)>($r6);
label4:
return 6;
catch java.lang.NumberFormatException from label1 to label2 with label3;
}
The bytecode transformed from the jimple file:
private static int getStartLevel();
descriptor: ()I
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=4, locals=2, args_size=0
0: ldc #79 // String osgi.startLevel
2: invokestatic #395 // Method org/eclipse/osgi/framework/internal/core/FrameworkProperties.getProperty:(Ljava/lang/String;)Ljava/lang/String;
5: astore_1
6: aload_1
7: ifnull 53
10: aload_1
11: invokestatic #594 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
14: istore_1
15: iload_1
16: ireturn
17: astore_0
18: getstatic #308 // Field debug:Z
21: ifeq 53
24: getstatic #647 // Field java/lang/System.out:Ljava/io/PrintStream;
27: new #422 // class java/lang/StringBuffer
30: dup
31: ldc_w #649 // String Start level =
34: invokespecial #439 // Method java/lang/StringBuffer."
Thanks, that confirms my suspicion: in the original bytecode the trap covers the ireturn (bytecode 14), but in the bytecode that Soot generates it is not covered (bytecode 16, but the trap ends at 15). In fact it appears that the Jimple code is wrong already. I believe that it should rather read:
private static int getStartLevel()
{
java.lang.String r0, $r6;
int $i0;
java.lang.NumberFormatException $r1;
boolean $z0;
java.lang.StringBuffer $r2, $r4, $r5;
java.io.PrintStream $r3;
r0 = staticinvoke <org.eclipse.osgi.framework.internal.core.FrameworkProperties: java.lang.String getProperty(java.lang.String)>("osgi.startLevel");
if r0 == null goto label4;
label1:
$i0 = staticinvoke <java.lang.Integer: int parseInt(java.lang.String)>(r0);
return $i0;
label3:
$r1 := @caughtexception;
$z0 = <org.eclipse.core.runtime.adaptor.EclipseStarter: boolean debug>;
if $z0 == 0 goto label4;
$r3 = <java.lang.System: java.io.PrintStream out>;
$r2 = new java.lang.StringBuffer;
specialinvoke $r2.<java.lang.StringBuffer: void <init>(java.lang.String)>("Start level = ");
$r4 = virtualinvoke $r2.<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>(r0);
$r5 = virtualinvoke $r4.<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>(" parsed. Using hardcoded default: 6");
$r6 = virtualinvoke $r5.<java.lang.StringBuffer: java.lang.String toString()>();
virtualinvoke $r3.<java.io.PrintStream: void println(java.lang.String)>($r6);
label4:
return 6;
catch java.lang.NumberFormatException from label1 to label3 with label3;
}
The mistake is probably somewhere in ExceptionalUnitGraph. @myspringchen could you devote some time yourself to debug this?
Thank you, Eric. It's a method from the Dacapo benchmark.
Actually I have partially solved my problem (let the bytecode pass verification) by rewriting the Jimple code: before the use of r0 in the exception handling part, I redefine r0 (see next). My work can be continued now.
Regards,
Yuting
r0 = staticinvoke <org.eclipse.osgi.framework.internal.core.FrameworkProperties: java.lang.String getProperty(java.lang.String)>("osgi.startLevel");
if r0 == null goto label4;
label1:
$i0 = staticinvoke <java.lang.Integer: int parseInt(java.lang.String)>(r0);
label2:
return $i0;
label3:
$r1 := @caughtexception;
$z0 =
label4: return 6;
catch java.lang.NumberFormatException from label1 to label2 with label3;
}
@myspringchen Closed due to inactivity. Please re-open if still relevant.
Hi, I recently used soot to perform some jimple-class transformations. It seems that the next method is not correctly transformed. The Jimple code is correct, while JVM throws a verify error when it loads the transformed code. I thought the exception handling triggers the mis-transformation.
I used the asm-backend.
Thank you.
Yuting
public static int foo2() { java.lang.String r0; int $i0; java.lang.Exception $r1; boolean $z0; java.lang.StringBuffer $r2;
public static int foo2(); descriptor: ()I flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=2, args_size=0 0: new #19 // class java/lang/String 3: astore_1 4: aload_1 5: invokespecial #20 // Method java/lang/String."":()V
8: aload_1
9: ifnull 35
12: ldc #22 // String 5
14: invokestatic #28 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
17: istore_1
18: iload_1
19: ireturn
20: astore_0
21: new #30 // class java/lang/StringBuffer
24: dup
25: ldc #32 // String
27: invokespecial #35 // Method java/lang/StringBuffer."":(Ljava/lang/String;)V
30: aload_1
31: invokevirtual #39 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
34: pop
35: bipush 6
37: ireturn
Exception table:
from to target type
12 18 20 Class java/lang/Exception
StackMapTable: number_of_entries = 2
frame_type = 84 / same_locals_1_stack_item /
stack = [ class java/lang/Exception ]
frame_type = 14 / same /
Exception Details: Location: Search.foo2()I @30: aload_1 Reason: Type top (current frame, locals[1]) is not assignable to reference type Current Frame: bci: @30 flags: { } locals: { 'java/lang/Exception' } stack: { 'java/lang/StringBuffer' }