Skip to content

Fix out-of-bounds type stack read after rethrow in c-writer#2798

Open
aizu-m wants to merge 2 commits into
WebAssembly:mainfrom
aizu-m:c-writer-rethrow-underflow
Open

Fix out-of-bounds type stack read after rethrow in c-writer#2798
aizu-m wants to merge 2 commits into
WebAssembly:mainfrom
aizu-m:c-writer-rethrow-underflow

Conversation

@aizu-m

@aizu-m aizu-m commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

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.

Comment thread src/test-c-writer.cc Outdated
0x36, 0x02, 0x00, // i32.store (unreachable)
0x0b, // end try
0x0b, // end func
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make this a unit test rather then a normal file-based test in test/wasm2c/?

Also does this mean non of the spec tests have this case? Perhaps we should upstream something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to a file-based test: test/wasm2c/unreachable-after-rethrow.txt, run-spec-wasm2c with --enable-exceptions. Verified it aborts on the unpatched tree at c-writer.cc:1246 and passes (1/1) with the fix in place. Dropped the gtest and the Features plumbing it needed.

On the spec suite: the existing exception-handling tests all translate through wasm2c cleanly, so none of them put an operand-consuming instruction in the unreachable tail after rethrow, which is what drives the StackVar underflow. legacy/rethrow.wast is the closest but its rethrow sits at the end of the block. Agreed it's worth having upstream. I can send a case over to the testsuite repo separately and keep this local regression test in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants