Skip to content

[interp] Fix wasm-interp stack cleanup for tail calls - #2835

Open
KKiiim wants to merge 1 commit into
WebAssembly:mainfrom
KKiiim:fix-interp-return-call
Open

[interp] Fix wasm-interp stack cleanup for tail calls#2835
KKiiim wants to merge 1 commit into
WebAssembly:mainfrom
KKiiim:fix-interp-return-call

Conversation

@KKiiim

@KKiiim KKiiim commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix incorrect value-stack cleanup when lowering return_call and return_call_indirect in wasm-interp.

The interpreter emits drop_keep before a tail call to discard values below the callee arguments. The cleanup counts must be calculated from the validator's current type stack. Previously, the return-call validator was invoked before that calculation, consuming the tail-call operands and making the computed drop count incorrect.

As a result, dead operand-stack values could survive an imported tail call and later be observed as a caller result.

Fix

Get the callee parameter count from the validator, then compute drop_keep and catch cleanup before validation consumes the operands. Invalid indexes remain handled by the validator.

Tests

Add minimal direct and indirect imported tail-call regressions where a dead value below the tail-call arguments must not escape into the caller.
Verified with the focused interpreter tail-call tests and the original fuzz reproducer, which now returns i32:0.

@KKiiim
KKiiim force-pushed the fix-interp-return-call branch 2 times, most recently from a1d3749 to fee30e3 Compare August 25, 2026 09:29
Comment thread src/interp/binary-reader-interp.cc Outdated

FuncType& func_type = func_types_[func_index];
Index param_count;
if (!validator_.GetFuncParamCount(func_index, &param_count)) {

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 pull this information from the validator if we have our own func_types_ array?

IIUC that validator is not normally the source of this kind of information is it?

Comment thread src/interp/binary-reader-interp.cc Outdated
Index param_count;
if (!validator_.GetFuncParamCount(func_index, &param_count)) {
return validator_.OnReturnCall(GetLocation(),
Var(func_index, GetLocation()));

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.

Can you add a comment as to why we have this early return when param count is zero? Can't the generic code below handle zero params?

@KKiiim

KKiiim commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Yes. Thanks for your advice.

Current change: Compute and emit the correct drop_keep cleanup before validation consumes the tail-call arguments.

This bug can be reproduced using the function f. f should return 0, not 777.

(module
  (type $i_i (func (param i32) (result i32)))
  (import "host" "print" (func $imported (type $i_i)))

  (func $tail (result i32)
    i32.const 777
    i32.const 0
    return_call $imported)

  (func (export "f") (result i32)
    (local i32)
    call $tail
    local.get 0
    return)
)

@KKiiim
KKiiim force-pushed the fix-interp-return-call branch 2 times, most recently from 1b8220a to 6fe4e91 Compare August 26, 2026 05:52
@KKiiim
KKiiim force-pushed the fix-interp-return-call branch from 6fe4e91 to e430599 Compare August 26, 2026 06:23
@KKiiim
KKiiim requested a review from sbc100 August 26, 2026 06:33
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