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 { ...@@ -879,6 +879,7 @@ namespace internal {
TFS(ThrowWasmTrapElemSegmentDropped) \ TFS(ThrowWasmTrapElemSegmentDropped) \
TFS(ThrowWasmTrapTableOutOfBounds) \ TFS(ThrowWasmTrapTableOutOfBounds) \
TFS(ThrowWasmTrapBrOnExnNullRef) \ TFS(ThrowWasmTrapBrOnExnNullRef) \
TFS(ThrowWasmTrapRethrowNullRef) \
\ \
/* WeakMap */ \ /* WeakMap */ \
TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \ TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \
......
...@@ -60,7 +60,16 @@ TF_BUILTIN(WasmRethrow, WasmBuiltinsAssembler) { ...@@ -60,7 +60,16 @@ TF_BUILTIN(WasmRethrow, WasmBuiltinsAssembler) {
TNode<Object> exception = CAST(Parameter(Descriptor::kException)); TNode<Object> exception = CAST(Parameter(Descriptor::kException));
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
TNode<Context> context = LoadContextFromInstance(instance); TNode<Context> context = LoadContextFromInstance(instance);
Label nullref(this, Label::kDeferred);
GotoIf(TaggedEqual(NullConstant(), exception), &nullref);
TailCallRuntime(Runtime::kReThrow, context, exception); 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) { TF_BUILTIN(WasmTraceMemory, WasmBuiltinsAssembler) {
......
...@@ -1597,7 +1597,8 @@ enum class LoadSensitivity { ...@@ -1597,7 +1597,8 @@ enum class LoadSensitivity {
V(TrapDataSegmentDropped) \ V(TrapDataSegmentDropped) \
V(TrapElemSegmentDropped) \ V(TrapElemSegmentDropped) \
V(TrapTableOutOfBounds) \ V(TrapTableOutOfBounds) \
V(TrapBrOnExnNullRef) V(TrapBrOnExnNullRef) \
V(TrapRethrowNullRef)
enum KeyedAccessLoadMode { enum KeyedAccessLoadMode {
STANDARD_LOAD, STANDARD_LOAD,
......
...@@ -552,6 +552,7 @@ namespace internal { ...@@ -552,6 +552,7 @@ namespace internal {
T(WasmTrapElemSegmentDropped, "element segment has been dropped") \ T(WasmTrapElemSegmentDropped, "element segment has been dropped") \
T(WasmTrapTableOutOfBounds, "table access out of bounds") \ T(WasmTrapTableOutOfBounds, "table access out of bounds") \
T(WasmTrapBrOnExnNullRef, "br_on_exn on nullref value") \ T(WasmTrapBrOnExnNullRef, "br_on_exn on nullref value") \
T(WasmTrapRethrowNullRef, "rethrowing nullref value") \
T(WasmExceptionError, "wasm exception") \ T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \ /* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \ T(AsmJsInvalid, "Invalid asm.js: %") \
......
...@@ -2121,7 +2121,6 @@ Node* WasmGraphBuilder::BuildDecodeException64BitValue(Node* values_array, ...@@ -2121,7 +2121,6 @@ Node* WasmGraphBuilder::BuildDecodeException64BitValue(Node* values_array,
} }
Node* WasmGraphBuilder::Rethrow(Node* except_obj) { Node* WasmGraphBuilder::Rethrow(Node* except_obj) {
needs_stack_check_ = true;
// TODO(v8:8091): Currently the message of the original exception is not being // 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 // preserved when rethrown to the console. The pending message will need to be
// saved when caught and restored here while being rethrown. // saved when caught and restored here while being rethrown.
...@@ -2132,9 +2131,7 @@ Node* WasmGraphBuilder::Rethrow(Node* except_obj) { ...@@ -2132,9 +2131,7 @@ Node* WasmGraphBuilder::Rethrow(Node* except_obj) {
Operator::kNoProperties, StubCallMode::kCallWasmRuntimeStub); Operator::kNoProperties, StubCallMode::kCallWasmRuntimeStub);
Node* call_target = mcgraph()->RelocatableIntPtrConstant( Node* call_target = mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmRethrow, RelocInfo::WASM_STUB_CALL); wasm::WasmCode::kWasmRethrow, RelocInfo::WASM_STUB_CALL);
return SetEffectControl( return gasm_->Call(call_descriptor, call_target, except_obj);
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), call_target,
except_obj, effect(), control()));
} }
Node* WasmGraphBuilder::ExceptionTagEqual(Node* caught_tag, Node* WasmGraphBuilder::ExceptionTagEqual(Node* caught_tag,
......
...@@ -3121,6 +3121,7 @@ class ThreadImpl { ...@@ -3121,6 +3121,7 @@ class ThreadImpl {
case kExprRethrow: { case kExprRethrow: {
HandleScope handle_scope(isolate_); // Avoid leaking handles. HandleScope handle_scope(isolate_); // Avoid leaking handles.
WasmValue ex = Pop(); WasmValue ex = Pop();
if (ex.to_anyref()->IsNull()) return DoTrap(kTrapRethrowNullRef, pc);
CommitPc(pc); // Needed for local unwinding. CommitPc(pc); // Needed for local unwinding.
if (!DoRethrowException(ex)) return; if (!DoRethrowException(ex)) return;
ReloadFromFrameOnException(&decoder, &code, &pc, &limit); ReloadFromFrameOnException(&decoder, &code, &pc, &limit);
......
...@@ -232,3 +232,48 @@ load("test/mjsunit/wasm/exceptions-utils.js"); ...@@ -232,3 +232,48 @@ load("test/mjsunit/wasm/exceptions-utils.js");
assertTraps(kTrapBrOnExnNullRef, () => instance.exports.call_import(2)); assertTraps(kTrapBrOnExnNullRef, () => instance.exports.call_import(2));
assertEquals(kNoMatch, instance.exports.call_import(3)); 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; ...@@ -502,6 +502,7 @@ let kTrapDataSegmentDropped = 10;
let kTrapElemSegmentDropped = 11; let kTrapElemSegmentDropped = 11;
let kTrapTableOutOfBounds = 12; let kTrapTableOutOfBounds = 12;
let kTrapBrOnExnNullRef = 13; let kTrapBrOnExnNullRef = 13;
let kTrapRethrowNullRef = 14;
let kTrapMsgs = [ let kTrapMsgs = [
"unreachable", "unreachable",
...@@ -517,7 +518,8 @@ let kTrapMsgs = [ ...@@ -517,7 +518,8 @@ let kTrapMsgs = [
"data segment has been dropped", "data segment has been dropped",
"element segment has been dropped", "element segment has been dropped",
"table access out of bounds", "table access out of bounds",
"br_on_exn on nullref value" "br_on_exn on nullref value",
"rethrowing nullref value"
]; ];
function assertTraps(trap, code) { 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