diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 447c22497d3..8d793045dfb 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -304,6 +304,13 @@ struct ContinuationStore { // Set when we are resuming execution, that is, re-winding the stack. bool resuming = false; + + // On traps or other errors that unwind the stack, we reset the continuation + // store to return to a clean state ahead of further calls to exports. + void clear() { + continuations.clear(); + resuming = false; + } }; // Execute an expression @@ -537,7 +544,7 @@ class ExpressionRunner : public OverriddenVisitor { #if WASM_INTERPRETER_DEBUG std::cout << indent() << "clear continuations\n"; #endif - continuationStore = std::make_shared(); + continuationStore->clear(); } } diff --git a/test/lit/exec/continuation-leak.wast b/test/lit/exec/continuation-leak.wast new file mode 100644 index 00000000000..b760d95ccff --- /dev/null +++ b/test/lit/exec/continuation-leak.wast @@ -0,0 +1,26 @@ +;; RUN: wasm-opt %s -all --fuzz-exec-before --fuzz-exec-second=%s.second -q -o /dev/null 2>&1 | filecheck %s + +;; Check that clearing the continuation store in linked modules clears it in-place, +;; so that continuations leaked from the primary module do not affect the second module. + +(module + (type $func_t (func)) + (type $cont_t (cont $func_t)) + (tag $tag) + + (func $f_suspend + (suspend $tag) + ) + + (func $test1 (export "test1") + (local $c (ref $cont_t)) + (local.set $c (cont.new $cont_t (ref.func $f_suspend))) + (resume $cont_t (local.get $c)) + ) +) + +;; CHECK: [fuzz-exec] export test1 +;; CHECK-NEXT: [exception thrown: unhandled suspend] +;; CHECK: [fuzz-exec] running second module +;; CHECK-NEXT: [fuzz-exec] export test2 +;; CHECK-NEXT: [exception thrown: unhandled suspend] diff --git a/test/lit/exec/continuation-leak.wast.second b/test/lit/exec/continuation-leak.wast.second new file mode 100644 index 00000000000..70a276176ae --- /dev/null +++ b/test/lit/exec/continuation-leak.wast.second @@ -0,0 +1,7 @@ +(module + (tag $tag) + + (func $test2 (export "test2") + (suspend $tag) + ) +)