我如何知道在字节码级别抛出的异常类型?

时间:2013-09-12 17:04:33

标签: java exception exception-handling bytecode static-analysis

显式调用 throw 语句在字节码级别用 athrow 指令表示。

例如,下面的代码段:

private static SQLException thrower() throws SQLException
{
    throw new SQLException();
}

被翻译成以下字节码:

   private static java.sql.SQLException thrower()   throws java.sql.SQLException;
   Signature: ()Ljava/sql/SQLException;
   Code:
   0:   new #29; //class java/sql/SQLException
   3:   dup
   4:   invokespecial   #31; //Method java/sql/SQLException."<init>":()V
   7:   athrow

我的问题是:通过仅分析字节码,我怎么知道抛出的异常的类型?

Obs。:值得一提的是,当我们在源代码中调用 throw 语句时,我们并不总是实例化一个新的异常类型。因此,查看 new 指令的参数类型不是解决方案。

3 个答案:

答案 0 :(得分:2)

这是不可能的,因为给定的指令可能会抛出多种类型的异常。

考虑代码

throw foo ? new ClassCastException() : new IOException();

在更复杂的情况下,您可能会抛出一些在运行时确定的类型,或者甚至是从在运行时构造的类创建的。

答案 1 :(得分:0)

这个问题太笼统了。所以,这是通用答案。

您需要识别使athrow操作码消耗的值的指令或指令,然后将数据流传递到创建该值的位置。

答案 2 :(得分:0)

异常实例是否来自 new 指令或其他内容并不重要。所有说明都是打字的。所以它可能来自字段读取,方法调用或作为参数传递......在所有情况下它都具有声明的类型。唯一的区别是,对于 new 指令,您现在声明的类型将完全匹配运行时类型。在所有其他情况下,它可以是声明类型的子类。

但是你必须解释方法并模拟指令对局部变量和操作数堆栈的影响,以找出最顶层堆栈条目对 athrow 指令的类型。