Interpreter: Fix delegate through try_table (#9234)
When an exception is delegated to an outer scope via legacy
try-delegate, the interpreter would previously fail to propagate it
through try_table to the delegate target.
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 8f79022..d5e358a 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -4963,6 +4963,12 @@
try {
return self()->visit(curr->body);
} catch (const WasmException& e) {
+ // If delegation is in progress, try_table cannot be the target of a
+ // legacy try-delegate, so don't handle it and just rethrow.
+ if (scope->currDelegateTarget.is()) {
+ throw;
+ }
+
auto exnData = e.exn.getExnData();
for (size_t i = 0; i < curr->catchTags.size(); i++) {
auto catchTag = curr->catchTags[i];
diff --git a/test/lit/exec/eh-legacy.wast b/test/lit/exec/eh-legacy.wast
index 6a95652..3c03550 100644
--- a/test/lit/exec/eh-legacy.wast
+++ b/test/lit/exec/eh-legacy.wast
@@ -47,6 +47,46 @@
)
)
)
+
+ ;; CHECK: [fuzz-exec] export try-delegate-caller-through-try_table
+ ;; CHECK-NEXT: [exception thrown: e-i32 5]
+ (func $try-delegate-caller-through-try_table (export "try-delegate-caller-through-try_table")
+ ;; Delegation to the caller should bypass an intermediate try_table.
+ (block $catch
+ (try_table (catch_all $catch)
+ (try
+ (do
+ (throw $e-i32 (i32.const 5))
+ )
+ (delegate 1)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] export try-delegate-try-through-try_table
+ ;; CHECK-NEXT: [fuzz-exec] note result: try-delegate-try-through-try_table => 6
+ (func $try-delegate-try-through-try_table (export "try-delegate-try-through-try_table") (result i32)
+ ;; Delegation to an outer try should also bypass an intermediate try_table.
+ (try $l0 (result i32)
+ (do
+ (block $catch
+ (try_table (catch_all $catch)
+ (try
+ (do
+ (throw $e-i32 (i32.const 6))
+ )
+ (delegate $l0)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (catch $e-i32
+ (pop i32)
+ )
+ )
+ )
)
;; CHECK: [fuzz-exec] export throw
;; CHECK-NEXT: [exception thrown: e-i32 1]
@@ -58,7 +98,15 @@
;; CHECK: [fuzz-exec] export try-delegate
;; CHECK-NEXT: [exception thrown: e-i32 4]
+
+;; CHECK: [fuzz-exec] export try-delegate-caller-through-try_table
+;; CHECK-NEXT: [exception thrown: e-i32 5]
+
+;; CHECK: [fuzz-exec] export try-delegate-try-through-try_table
+;; CHECK-NEXT: [fuzz-exec] note result: try-delegate-try-through-try_table => 6
;; CHECK-NEXT: [fuzz-exec] comparing catchless-try
;; CHECK-NEXT: [fuzz-exec] comparing throw
;; CHECK-NEXT: [fuzz-exec] comparing try-catch
;; CHECK-NEXT: [fuzz-exec] comparing try-delegate
+;; CHECK-NEXT: [fuzz-exec] comparing try-delegate-caller-through-try_table
+;; CHECK-NEXT: [fuzz-exec] comparing try-delegate-try-through-try_table