簡體   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