异常处理期间的烟灰、标识 stmts 和控制流



我正在尝试用soot编写一个 try-catch 块。

让我们反编译

public class A {
public static void main(String[] args) {
try{
String a = args[9999];
}catch(Throwable t){
t.printStackTrace();
}
System.out.println("Hello World");
}
}

我将在问题的末尾添加完整的反编译。重要的部分是

0: aload_0
1: sipush        9999
4: aaload
5: astore_1
6: goto          14
9: astore_1
10: aload_1
11: invokevirtual #3                  // Method java/lang/Throwable.printStackTrace:()V
14: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc           #5                  // String Hello World
19: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return

Exception table:
from    to  target type
0     6     9   Class java/lang/Throwable

因此,这意味着如果任何指令 0-6 抛出异常,控制将被重新路由到9并且执行将像正常一样继续,astore_1是在局部变量中存储对异常对象的引用。

但是,我正在尝试在soot中生成一个try-catch块,我发现了一个实际上可以执行以下操作的示例:CatchWrapInstrumenter.java

根据文档,newTrap

使用给定的 Stmt 处理程序为给定 Stmt 范围内的给定异常构造新的 JTrap。

所以当我们看到

b.getTraps().add(Jimple.v().newTrap(thrwCls, sFirstNonId, sGotoLast, sCatch));

我们可以猜测这本质上是在说"如果在sFirstNonIdsGotoLast之间的任何 stmts 中抛出类型thrwCls的异常,则在sCatch跳转到处理程序。

到目前为止,这符合预期。

现在,困扰我的是

Stmt sCatch = Jimple.v().newIdentityStmt(lException1, Jimple.v().newCaughtExceptionRef());

是一个标识stmt。

因为身份标准

是定义要预加载的局部变量的语句(在方法输入时) 具有特殊值,例如参数或此值。

例如,l0 := @this:A 将局部 l0 定义为方法的 this。

此标识是必需的,因为局部变量未编号(通常此变量是字节码级别的局部变量插槽 0 中的变量。

(烟尘纸第31页[编号23])

所以 - 再次以class A为例 - 如果我要生成(简化)

Sting a;Throwable t;PrintStream out;
a = arg[9990]               //stmt1
goto stmt5                  //stmt2
t := thrownException;       //stmt3
t.printStackTrace();        //stmt4
out = System.out;           //stmt5
out.println("Hello World")  //stmt6

有意注册

newTrap(exception=java.lang.Throwable, beginStmt=stmt1,endStmt=stmt2,handlerStmt=stmt3)

,正如我基于反编译A.class一样,这实际上是非法的,因为t := thrownException应该是"预加载的(在方法输入时)"。

然而,与此同时,如果要信任烟尘纸第86页[编号78]上的例子,这正是我们要做的。

这种"预加载"当时还不存在的东西的概念对我来说没有多大意义,让我觉得我在控制流上可能是错的,尽管我不知道怎么做。

有人可以解释一下这里实际发生了什么吗?

小型 try-catch 示例的完整反编译代码:

public class A
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref          #8.#28         // java/lang/Object."<init>":()V
#2 = Class              #29            // java/lang/Throwable
#3 = Methodref          #2.#30         // java/lang/Throwable.printStackTrace:()V
#4 = Fieldref           #31.#32        // java/lang/System.out:Ljava/io/PrintStream;
#5 = String             #33            // Hello World
#6 = Methodref          #34.#35        // java/io/PrintStream.println:(Ljava/lang/String;)V
#7 = Class              #36            // A
#8 = Class              #37            // java/lang/Object
#9 = Utf8               <init>
#10 = Utf8               ()V
#11 = Utf8               Code
#12 = Utf8               LineNumberTable
#13 = Utf8               LocalVariableTable
#14 = Utf8               this
#15 = Utf8               LA;
#16 = Utf8               main
#17 = Utf8               ([Ljava/lang/String;)V
#18 = Utf8               a
#19 = Utf8               Ljava/lang/String;
#20 = Utf8               t
#21 = Utf8               Ljava/lang/Throwable;
#22 = Utf8               args
#23 = Utf8               [Ljava/lang/String;
#24 = Utf8               StackMapTable
#25 = Class              #29            // java/lang/Throwable
#26 = Utf8               SourceFile
#27 = Utf8               A.java
#28 = NameAndType        #9:#10         // "<init>":()V
#29 = Utf8               java/lang/Throwable
#30 = NameAndType        #38:#10        // printStackTrace:()V
#31 = Class              #39            // java/lang/System
#32 = NameAndType        #40:#41        // out:Ljava/io/PrintStream;
#33 = Utf8               Hello World
#34 = Class              #42            // java/io/PrintStream
#35 = NameAndType        #43:#44        // println:(Ljava/lang/String;)V
#36 = Utf8               A
#37 = Utf8               java/lang/Object
#38 = Utf8               printStackTrace
#39 = Utf8               java/lang/System
#40 = Utf8               out
#41 = Utf8               Ljava/io/PrintStream;
#42 = Utf8               java/io/PrintStream
#43 = Utf8               println
#44 = Utf8               (Ljava/lang/String;)V
{
public A();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1                  // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
LocalVariableTable:
Start  Length  Slot  Name   Signature
0       5     0  this   LA;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: sipush        9999
4: aaload
5: astore_1
6: goto          14
9: astore_1
10: aload_1
11: invokevirtual #3                  // Method java/lang/Throwable.printStackTrace:()V
14: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc           #5                  // String Hello World
19: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
Exception table:
from    to  target type
0     6     9   Class java/lang/Throwable
LineNumberTable:
line 4: 0
line 7: 6
line 5: 9
line 6: 10
line 8: 14
line 9: 22
LocalVariableTable:
Start  Length  Slot  Name   Signature
6       0     1     a   Ljava/lang/String;
10       4     1     t   Ljava/lang/Throwable;
0      23     0  args   [Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 73 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 4 /* same */
}
SourceFile: "A.java"

我认为你对IdentityStmts的概念有误解。不同的IdentityStmts的共同点是它们分配的值"神奇地从天而降"。在方法输入中,这些是参数和"this",在异常处理程序中,这些是抛出的异常。换句话说,它完全没问题,并且期望在处理程序开始的位置的方法主体中有一个带有异常引用的 IdentityStmt。Soot 的唯一假设是,如果语句是 Trap 的目标,即处理程序的开始,那么该处理程序中的第一个语句应该是具有适当异常引用的 IdentityStmt。

我希望这能回答你的问题。

相关内容

  • 没有找到相关文章

最新更新