2

I'm trying to write a try-catch block in soot.

Let's decompile

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

I will add the full decompilation to the end of the question. The important parts are

     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

and

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

So what this implies is that if any of the instructions 0-6 throw an exception, control will be re-routed to 9 and execution will continue as if normal, the astore_1 there being the storing of the reference to the exception object in a local variable.

However, I'm trying to generate a try-catch block in soot and I found one example that actually does something like this: CatchWrapInstrumenter.java

According to documentation, newTrap

Constructs a new JTrap for the given exception on the given Stmt range with the given Stmt handler.

So when we see

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

We can guess that this essentially is saying "if there's an exception of type thrwCls thrown in any of the stmts between sFirstNonId, sGotoLast, jump to the handler at sCatch.

So far, this matches expectations.

Now, what bothers me, is that

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

is an identity stmt.

Because identity stmts

are statements which define locals to be pre-loaded (upon method entry) with special values such as parameters or the this value.

For example, l0 := @this: A defines local l0 to be the this of the method.

This identification is necessary because the local variables are not numbered (normally the this variable is the variable in local variable slot 0 at the bytecode level.)

(page 31 [numbered 23] in the soot paper)

So -- taking again class A as an example -- if I were to generate (simplified)

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

with the intention to register

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

, as I would have based on the decompiled A.class, this would actually be illegal because t := thrownException is supposed to be "pre-loaded (upon method entry)".

Yet at the same time, this is exactly what we are to do if the example on page 86 [numbered 78] of the soot paper is to be trusted.

This concept of "pre-loading" something that does not yet exists at the time it does, doesn't make terribly much sense to me and makes me think I could be wrong on the control flow, though I do not see how.

Could somebody please explain what is actually happening, here?

Full decompiled code of the small try-catch example:

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"
User1291
  • 6,231
  • 5
  • 34
  • 75
  • 1
    After looking at all your links, I’d say that this simply is an omission of the second use case, so don’t focus on “pre-loaded (upon method entry)”. It’s rather a place holder for entities not described by the `Stmt` objects, but rather predefined by Java bytecode semantics, like the `this` reference, method parameters, and the throwable instance passed to exception handlers on the stack. Compare with [the superinterface](https://soot-build.cs.uni-paderborn.de/public/origin/master/soot/soot-master/3.0.0/jdoc/soot/IdentityUnit.html): “…assigns … from one of {parameters, this, caughtexception}”… – Holger Nov 30 '17 at 16:32

1 Answers1

1

I think you have a misconception of the notion of IdentityStmts. What different IdentityStmts have in common is that they assign values that "magically fall from the sky". At method entry those are parameters and "this", and in exception handlers those are the thrown exceptions. In other words, it's totally fine and expected to have an IdentityStmt with an exception reference inside a method's body at the place where the handler begins. The only assumption that Soot has is that if a statement is a target of a Trap, i.e., the start of the handler, then the first statement in that handler should be an IdentityStmt with an appropriate exception reference.

I hope this answers your question.

Eric
  • 1,247
  • 1
  • 10
  • 19