Skip to content

Commit 11602da

Browse files
authored
Fix out-of-bounds type stack read after rethrow in c-writer (#2798)
wasm2c on a valid exceptions module, ASan/debug build: Assertion failed: (index < type_stack_.size()), function Write, file c-writer.cc, line 1246. Worked backwards from the StackVar read. The rethrow case in `Write(const ExprList&)` ends in `break`, so the loop carries on and emits the instructions after it. The validator has already marked those unreachable (`OnRethrow` makes the stack polymorphic), so a valid module can put operations there that pop operands which are not really on the stack. StackVar then underflows `type_stack_` and reads off the end. Release builds drop the assert and take the out-of-bounds read; `DropTypes` does an out-of-bounds erase on the same tail. br, br_table, return, unreachable, throw, throw_ref and the return_call family all return here to stop walking the list. rethrow was the one that fell through, so it now does the same. Repro: `(func try nop catch_all rethrow 0 i32.store end)` assembled with `--enable-exceptions`, then run through wasm2c.
1 parent f794a59 commit 11602da

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

src/c-writer.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4187,7 +4187,9 @@ void CWriter::Write(const ExprList& exprs) {
41874187
Write("wasm_rt_load_exception(", ex, "_tag, ", ex, "_size, ", ex, ");",
41884188
Newline());
41894189
WriteThrow();
4190-
} break;
4190+
// Stop processing this ExprList, since the following are unreachable.
4191+
return;
4192+
}
41914193

41924194
case ExprType::Try: {
41934195
const TryExpr& tryexpr = *cast<TryExpr>(&expr);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
;;; TOOL: run-spec-wasm2c
2+
;;; ARGS*: --enable-exceptions
3+
(module
4+
(memory 1)
5+
(func (export "test")
6+
try
7+
nop
8+
catch_all
9+
rethrow 0
10+
i32.store
11+
end))
12+
(assert_return (invoke "test"))
13+
(;; STDOUT ;;;
14+
1/1 tests passed.
15+
;;; STDOUT ;;)

0 commit comments

Comments
 (0)