Commit 404ce209 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm] Make rethrow trap on nullptr

The behaviour was clarified in the spec:
https://github.com/WebAssembly/exception-handling/pull/97

br_on_exn (which was done in another CL) and also rethrow should trap on
nullptr. This CL implements this by an explicit check in the builtin
called for rethrow.

R=jkummerow@chromium.org
CC=aheejin@chromium.org

Bug: v8:10128
Change-Id: Icb0f4e54991b3385917bf183efa825048db4cb82
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2115430
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66827}
parent bcc055c1
......@@ -879,6 +879,7 @@ namespace internal {
TFS(ThrowWasmTrapElemSegmentDropped) \
TFS(ThrowWasmTrapTableOutOfBounds) \
TFS(ThrowWasmTrapBrOnExnNullRef) \
TFS(ThrowWasmTrapRethrowNullRef) \
\
/* WeakMap */ \
TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \
......
......@@ -60,7 +60,16 @@ TF_BUILTIN(WasmRethrow, WasmBuiltinsAssembler) {
TNode<Object> exception = CAST(Parameter(Descriptor::kException));
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
TNode<Context> context = LoadContextFromInstance(instance);
Label nullref(this, Label::kDeferred);
GotoIf(TaggedEqual(NullConstant(), exception), &nullref);
TailCallRuntime(Runtime::kReThrow, context, exception);
BIND(&nullref);
MessageTemplate message_id = MessageTemplate::kWasmTrapRethrowNullRef;
TailCallRuntime(Runtime::kThrowWasmError, context,
SmiConstant(static_cast<int>(message_id)));
}
TF_BUILTIN(WasmTraceMemory, WasmBuiltinsAssembler) {
......
......@@ -1597,7 +1597,8 @@ enum class LoadSensitivity {
V(TrapDataSegmentDropped) \
V(TrapElemSegmentDropped) \
V(TrapTableOutOfBounds) \
V(TrapBrOnExnNullRef)
V(TrapBrOnExnNullRef) \
V(TrapRethrowNullRef)
enum KeyedAccessLoadMode {
STANDARD_LOAD,
......
......@@ -552,6 +552,7 @@ namespace internal {
T(WasmTrapElemSegmentDropped, "element segment has been dropped") \
T(WasmTrapTableOutOfBounds, "table access out of bounds") \
T(WasmTrapBrOnExnNullRef, "br_on_exn on nullref value") \
T(WasmTrapRethrowNullRef, "rethrowing nullref value") \
T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \
......
......@@ -2121,7 +2121,6 @@ Node* WasmGraphBuilder::BuildDecodeException64BitValue(Node* values_array,
}
Node* WasmGraphBuilder::Rethrow(Node* except_obj) {
needs_stack_check_ = true;
// TODO(v8:8091): Currently the message of the original exception is not being
// preserved when rethrown to the console. The pending message will need to be
// saved when caught and restored here while being rethrown.
......@@ -2132,9 +2131,7 @@ Node* WasmGraphBuilder::Rethrow(Node* except_obj) {
Operator::kNoProperties, StubCallMode::kCallWasmRuntimeStub);
Node* call_target = mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmRethrow, RelocInfo::WASM_STUB_CALL);
return SetEffectControl(
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), call_target,
except_obj, effect(), control()));
return gasm_->Call(call_descriptor, call_target, except_obj);
}
Node* WasmGraphBuilder::ExceptionTagEqual(Node* caught_tag,
......
......@@ -3121,6 +3121,7 @@ class ThreadImpl {
case kExprRethrow: {
HandleScope handle_scope(isolate_); // Avoid leaking handles.
WasmValue ex = Pop();
if (ex.to_anyref()->IsNull()) return DoTrap(kTrapRethrowNullRef, pc);
CommitPc(pc); // Needed for local unwinding.
if (!DoRethrowException(ex)) return;
ReloadFromFrameOnException(&decoder, &code, &pc, &limit);
......
......@@ -232,3 +232,48 @@ load("test/mjsunit/wasm/exceptions-utils.js");
assertTraps(kTrapBrOnExnNullRef, () => instance.exports.call_import(2));
assertEquals(kNoMatch, instance.exports.call_import(3));
})();
// 'rethrow' on a null-ref value should trap.
(function TestRethrowNullRefSimple() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let except = builder.addException(kSig_v_r);
builder.addFunction('rethrow_nullref', kSig_v_v)
.addBody([
kExprRefNull,
kExprRethrow
]).exportFunc();
let instance = builder.instantiate();
assertTraps(kTrapRethrowNullRef, () => instance.exports.rethrow_nullref());
})();
(function TestRethrowNullRefFromJS() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let except = builder.addException(kSig_v_i);
let imp = builder.addImport('imp', 'ort', kSig_i_i);
let kSuccess = 11;
builder.addFunction('call_import', kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprLocalGet, 0,
kExprCallFunction, imp,
kExprCatch,
kExprRethrow,
kExprEnd
]).exportFunc();
let instance;
function js_import(i) {
if (i == 0) return kSuccess; // Will return kSuccess.
if (i == 1) throw new Error('1'); // Will rethrow.
if (i == 2) throw null; // Will trap.
throw undefined; // Will rethrow.
}
instance = builder.instantiate({imp: {ort: js_import}});
assertEquals(kSuccess, instance.exports.call_import(0));
assertThrows(() => instance.exports.call_import(1), Error, '1');
assertTraps(kTrapRethrowNullRef, () => instance.exports.call_import(2));
assertThrowsEquals(() => instance.exports.call_import(3), undefined);
})();
......@@ -502,6 +502,7 @@ let kTrapDataSegmentDropped = 10;
let kTrapElemSegmentDropped = 11;
let kTrapTableOutOfBounds = 12;
let kTrapBrOnExnNullRef = 13;
let kTrapRethrowNullRef = 14;
let kTrapMsgs = [
"unreachable",
......@@ -517,7 +518,8 @@ let kTrapMsgs = [
"data segment has been dropped",
"element segment has been dropped",
"table access out of bounds",
"br_on_exn on nullref value"
"br_on_exn on nullref value",
"rethrowing nullref value"
];
function assertTraps(trap, code) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment