[wasm-gc] Fix br_on_null behavior in unreachable code

br_on_null should push a value on the stack, even in unreachable code.


Bug: v8:9495
Change-Id: Ic227c2f889b863a267a7ff5f33e539b43e66b42f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2567966
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71582}
This commit is contained in:
Manos Koukoutos 2020-12-02 12:12:34 +00:00 committed by Commit Bot
parent 818ba36e31
commit e2f858a887
2 changed files with 42 additions and 18 deletions

View File

@ -2474,30 +2474,39 @@ class WasmFullDecoder : public WasmDecoder<validate> {
Value ref_object = Pop(0);
Control* c = control_at(imm.depth);
TypeCheckBranchResult check_result = TypeCheckBranch(c, true);
if (V8_LIKELY(check_result == kReachableBranch)) {
switch (ref_object.type.kind()) {
case ValueType::kBottom:
UNREACHABLE(); // This can only happen in unreachable code.
case ValueType::kRef: {
Value* result = Push(ref_object.type);
switch (ref_object.type.kind()) {
// For bottom and non-nullable reference, simply forward the popped
// argument to the result.
case ValueType::kBottom:
DCHECK(check_result != kReachableBranch);
V8_FALLTHROUGH;
case ValueType::kRef: {
Value* result = Push(ref_object.type);
if (V8_LIKELY(check_result == kReachableBranch)) {
CALL_INTERFACE(PassThrough, ref_object, result);
break;
}
case ValueType::kOptRef: {
// We need to Push the result value after calling BrOnNull on
// the interface. Therefore we must sync the ref_object and
// result nodes afterwards (in PassThrough).
break;
}
case ValueType::kOptRef: {
// We need to Push the result value after calling BrOnNull on
// the interface. Therefore we must sync the ref_object and
// result nodes afterwards (in PassThrough).
if (V8_LIKELY(check_result == kReachableBranch)) {
CALL_INTERFACE_IF_REACHABLE(BrOnNull, ref_object, imm.depth);
Value* result =
Push(ValueType::Ref(ref_object.type.heap_type(), kNonNullable));
}
Value* result =
Push(ValueType::Ref(ref_object.type.heap_type(), kNonNullable));
if (V8_LIKELY(check_result == kReachableBranch)) {
CALL_INTERFACE(PassThrough, ref_object, result);
c->br_merge()->reached = true;
break;
}
default:
this->DecodeError("invalid argument type to br_on_null");
return 0;
break;
}
default:
this->DecodeError(
"br_on_null[0]: Expected object reference, found %s of type %s",
SafeOpcodeNameAt(ref_object.pc()), ref_object.type.name().c_str());
return 0;
}
return 1 + imm.length;
}

View File

@ -1096,7 +1096,6 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
FunctionSig sig_v_s(0, 1, &struct_type);
byte struct_consumer = builder.AddFunction(&sig_v_s);
ExpectValidates(sigs.v_v(), {WASM_BLOCK(WASM_UNREACHABLE, kExprBrOnNull, 0)});
ExpectValidates(sigs.i_v(), {WASM_UNREACHABLE, kExprRefIsNull});
ExpectValidates(sigs.v_v(), {WASM_UNREACHABLE, kExprRefAsNonNull, kExprDrop});
@ -1153,6 +1152,22 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
ExpectValidates(sigs.v_v(),
{WASM_UNREACHABLE, WASM_GC_OP(kExprRttSub), array_index,
WASM_GC_OP(kExprRttSub), array_index, kExprDrop});
ExpectValidates(sigs.v_v(), {WASM_UNREACHABLE, kExprBrOnNull, 0, WASM_DROP});
ExpectValidates(&sig_v_s, {WASM_UNREACHABLE, WASM_GET_LOCAL(0), kExprBrOnNull,
0, kExprCallFunction, struct_consumer});
ValueType opt_struct_type = ValueType::Ref(struct_index, kNullable);
FunctionSig sig_v_os(0, 1, &opt_struct_type);
ExpectValidates(&sig_v_os,
{WASM_UNREACHABLE, WASM_GET_LOCAL(0), kExprBrOnNull, 0,
kExprCallFunction, struct_consumer});
ExpectFailure(
sigs.v_v(), {WASM_UNREACHABLE, WASM_I32V(42), kExprBrOnNull, 0},
kAppendEnd,
"br_on_null[0]: Expected object reference, found i32.const of type i32");
}
TEST_F(FunctionBodyDecoderTest, If1) {