繁体   English   中英

处理Java字节码中的Try / Catch异常? (“堆栈高度不一致”)

[英]Dealing with Try/Catch Exceptions in Java bytecode? (“stack height inconsistent”)

我试图在java字节码中做一些错误处理。 我首先尝试实现一些类似catch的子例程,在那里我将检查错误情况,并跳转到相应的子例程,有点像:

  iconst_1
  iconst_0
  dup
  ifeq calldiverr
  goto enddivtest
calldiverr:
  jsr divError
enddivtest:
  idiv

...More instructions...

divError:
  getstatic java/lang/System/out Ljava/io/PrintStream;
  ldc "Oh dear you divided by 0!"
  invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V

上面的问题是当我有多个指令跳转到这个子程序时,我在运行字节码时收到一条错误信息,说堆栈高度不一致。

也许使用例外是解决这个问题的最佳方法?

通过一些谷歌搜索,我发现你可以创建Exception类的实例,并用以下内容初始化它们:

new java/lang/Exception
dup
ldc "exception message!"
invokespecial java/lang/Exception/<init>(Ljava/lang/String;)V

我还发现,你可以把他们athrow ,这似乎确定。

然而令我感到困惑的是如何捕获异常。 似乎有一个神奇的“异常表”将异常的抛出和捕获粘在一起,但我不知道如何从头开始编写字节码(以及使用Jasmin进行汇编)时定义其中一个。 有人可以告诉我创建异常表的秘诀吗? 并且可能给我一个与jasmin汇编的异常处理示例?

最后,我提出了一个比jsr更好的解决方案 - 在Jasmin中使用.method定义一个方法。 一旦检测到错误,我只是使用invokestatic来调用我的错误处理程序。

对于那些寻找实际异常处理的人 - 我认为在Jasmin中定义异常表可能是使用.catch完成的,但我没有调查它,因为方法定义解决了我的问题。

编辑:

我最后一定要看看.catch ,发现它真的很容易使用。 在这里记录

首先,值得指出的是,版本51.0中的类文件可能不包含jsr指令。 重复代码或使用方法。

在字节码的每一点,必须知道帧中每个元素的静态类型。 每个帧都不是调用堆栈。

一般来说,你不想玩巨大的筹码。 将临时存储在局部变量中以保持简单。

如果抛出异常,那么显然该框架可能已经从异常可能抛出的任何地方获取了内容。 因此,内容将被丢弃并替换为异常。 无论如何,您将无法返回并继续使用框架内容。

验证jsr的规则非常复杂,并且正如Tom所说,操作码已被弃用。 所以最好避免。

我对jsr记忆有点模糊,但......

(更新)Java字节码验证中有一条规则,即只要两个控制流连接在一起,堆栈深度必须在两个分支上相同。 jsr子例程从这个规则中被豁免到一个点 - 具有不同堆栈深度的多个异常点可以“到达”相同的jsr例程,但是从jsr例程条目到后续ret堆栈深度的净变化必须为零(或实际上减去1) ,因为异常原因总是在进入例程时被推入)。

此外,虽然jsr例程可以“逃逸”并分支回常规控制流,但如果这样做,则jsr不会免于连接点的堆栈深度规则。 这严重限制了您可以执行此操作的情况,因为可能会以不同的堆栈深度输入jsr例程。

(我毫无疑问仍然有一些错误,但这是我能做的最好的。)

(我不太明白你是如何计划“绕过”你的jsr问题的例外。)

(另外,Sun使字节码写入更加复杂,有4或5个(不记得哪个),这使得手动编码字节码几乎不可能。他们这样做是因为他们不知道怎么做得足够快以便击败否则是IBM的验证者,但这是另一回事。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM