[wasm][stack-switching] Throw on re-entrant suspender
Throw a wasm trap when trying to re-enter a suspender that is active or suspended. R=ahaas@chromium.org Bug: v8:12191 Change-Id: Ic448a15db29de14fb8d6bb8408af8fbaae82a2b4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3716481 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/main@{#81326}
This commit is contained in:
parent
e35039e773
commit
2071ce3b6b
@ -3017,7 +3017,10 @@ void AllocateContinuation(MacroAssembler* masm, Register function_data,
|
||||
__ Push(wasm_instance);
|
||||
__ Push(function_data);
|
||||
__ Push(suspender); // Argument.
|
||||
__ Move(kContextRegister, Smi::zero());
|
||||
__ LoadAnyTaggedField(
|
||||
kContextRegister,
|
||||
MemOperand(wasm_instance, wasm::ObjectAccess::ToTagged(
|
||||
WasmInstanceObject::kNativeContextOffset)));
|
||||
__ CallRuntime(Runtime::kWasmAllocateContinuation);
|
||||
__ Pop(function_data);
|
||||
__ Pop(wasm_instance);
|
||||
@ -3228,7 +3231,7 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
|
||||
__ LoadRoot(active_continuation, RootIndex::kActiveContinuation);
|
||||
SaveState(masm, active_continuation, rcx, &suspend);
|
||||
AllocateContinuation(masm, function_data, wasm_instance);
|
||||
Register target_continuation = rax; /* fixed */
|
||||
Register target_continuation = rax; // fixed
|
||||
// Save the old stack's rbp in r9, and use it to access the parameters in
|
||||
// the parent frame.
|
||||
// We also distribute the spill slots across the two stacks as needed by
|
||||
|
@ -650,6 +650,7 @@ namespace internal {
|
||||
T(WasmTrapStringOffsetOutOfBounds, "string offset out of bounds") \
|
||||
T(WasmTrapStringIsolatedSurrogate, \
|
||||
"Failed to encode string as UTF-8: contains unpaired surrogate") \
|
||||
T(WasmTrapReentrantSuspender, "re-entering an active/suspended suspender") \
|
||||
T(WasmExceptionError, "wasm exception") \
|
||||
/* Asm.js validation related */ \
|
||||
T(AsmJsInvalid, "Invalid asm.js: %") \
|
||||
|
@ -798,6 +798,11 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<WasmSuspenderObject> suspender = args.at<WasmSuspenderObject>(0);
|
||||
|
||||
if (suspender->state() != WasmSuspenderObject::kInactive) {
|
||||
return ThrowWasmError(isolate,
|
||||
MessageTemplate::kWasmTrapReentrantSuspender);
|
||||
}
|
||||
|
||||
// Update the continuation state.
|
||||
auto parent = handle(WasmContinuationObject::cast(
|
||||
isolate->root(RootIndex::kActiveContinuation)),
|
||||
|
@ -323,3 +323,44 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
let combined_promise = wrapped_export();
|
||||
assertPromiseResult(combined_promise, v => assertEquals(v, 42));
|
||||
})();
|
||||
|
||||
(function TestReenterActiveSuspenderFails() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let import_index = builder.addImport("m", "i", kSig_v_v);
|
||||
builder.addFunction("test", kSig_i_v)
|
||||
.addBody([
|
||||
kExprCallFunction, import_index,
|
||||
kExprI32Const, 0
|
||||
]).exportFunc();
|
||||
let wrapped_export;
|
||||
function js_import() {
|
||||
wrapped_export(); // Re-enter the same wrapped export.
|
||||
}
|
||||
let instance = builder.instantiate({m: {i: js_import}});
|
||||
let suspender = new WebAssembly.Suspender();
|
||||
wrapped_export = suspender.returnPromiseOnSuspend(instance.exports.test);
|
||||
assertThrows(wrapped_export, WebAssembly.RuntimeError,
|
||||
/re-entering an active\/suspended suspender/);
|
||||
})();
|
||||
|
||||
(function TestReenterSuspendedSuspenderFails() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let import_index = builder.addImport("m", "i", kSig_v_v);
|
||||
builder.addFunction("test", kSig_i_v)
|
||||
.addBody([
|
||||
kExprCallFunction, import_index,
|
||||
kExprI32Const, 0
|
||||
]).exportFunc();
|
||||
function js_import() {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
let instance = builder.instantiate({m: {i: js_import}});
|
||||
let suspender = new WebAssembly.Suspender();
|
||||
let wrapped_export = suspender.returnPromiseOnSuspend(instance.exports.test);
|
||||
let promise1 = wrapped_export();
|
||||
// Re-enter the suspender before resolving the promise.
|
||||
assertThrows(wrapped_export, WebAssembly.RuntimeError,
|
||||
/re-entering an active\/suspended suspender/);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user