Commit a40dd830 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm] Maintain existing values in TypeCheckStackAgainstMerge

Replacing existing values leads to type errors and printing wrong pcs in
errors.

Change-Id: I513eae0a7e0cb5764d307eb172a378d328ca3660
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2936596Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74953}
parent 723d1af0
...@@ -3156,7 +3156,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -3156,7 +3156,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
DECODE(CallIndirect) { DECODE(CallIndirect) {
CallIndirectImmediate<validate> imm(this, this->pc_ + 1); CallIndirectImmediate<validate> imm(this, this->pc_ + 1);
if (!this->Validate(this->pc_ + 1, imm)) return 0; if (!this->Validate(this->pc_ + 1, imm)) return 0;
Value index = Peek(0, 0, kWasmI32); Value index =
Peek(0, static_cast<int>(imm.sig->parameter_count()), kWasmI32);
ArgVector args = PeekArgs(imm.sig, 1); ArgVector args = PeekArgs(imm.sig, 1);
ReturnVector returns = CreateReturnValues(imm.sig); ReturnVector returns = CreateReturnValues(imm.sig);
CALL_INTERFACE_IF_OK_AND_REACHABLE(CallIndirect, index, imm, args.begin(), CALL_INTERFACE_IF_OK_AND_REACHABLE(CallIndirect, index, imm, args.begin(),
...@@ -3513,13 +3514,17 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -3513,13 +3514,17 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}); });
} }
V8_INLINE void EnsureStackArguments(int count) { // In reachable code, check if there are at least {count} values on the stack.
// In unreachable code, if there are less than {count} values on the stack,
// insert a number of unreachable values underneath the current values equal
// to the difference, and return that number.
V8_INLINE int EnsureStackArguments(int count) {
uint32_t limit = control_.back().stack_depth; uint32_t limit = control_.back().stack_depth;
if (V8_LIKELY(stack_size() >= count + limit)) return; if (V8_LIKELY(stack_size() >= count + limit)) return 0;
EnsureStackArguments_Slow(count, limit); return EnsureStackArguments_Slow(count, limit);
} }
V8_NOINLINE void EnsureStackArguments_Slow(int count, uint32_t limit) { V8_NOINLINE int EnsureStackArguments_Slow(int count, uint32_t limit) {
if (!VALIDATE(control_.back().unreachable())) { if (!VALIDATE(control_.back().unreachable())) {
int index = count - stack_size() - 1; int index = count - stack_size() - 1;
NotEnoughArgumentsError(index); NotEnoughArgumentsError(index);
...@@ -3540,6 +3545,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -3540,6 +3545,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
for (int i = 0; i < additional_values; i++) { for (int i = 0; i < additional_values; i++) {
stack_base[i] = UnreachableValue(this->pc_); stack_base[i] = UnreachableValue(this->pc_);
} }
return additional_values;
} }
// Peeks arguments as required by signature. // Peeks arguments as required by signature.
...@@ -4955,19 +4961,18 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -4955,19 +4961,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
Peek(depth, i, (*merge)[i].type); Peek(depth, i, (*merge)[i].type);
} }
if (push_branch_values) { if (push_branch_values) {
Drop(drop_values); uint32_t inserted_value_count =
Drop(arity); static_cast<uint32_t>(EnsureStackArguments(drop_values + arity));
// {Drop} is adaptive for polymorphic stacks: it might drop fewer values if (inserted_value_count > 0) {
// than requested. So ensuring stack space here is not redundant. // EnsureStackSpace may have inserted unreachable values into the bottom
EnsureStackSpace(drop_values + arity); // of the stack. If so, mark them with the correct type. If drop values
// Push values of the correct type onto the stack. // were also inserted, disregard them, as they will be dropped anyway.
for (int i = 0; i < static_cast<int>(arity); i++) { Value* stack_base = stack_value(drop_values + arity);
Push(CreateValue((*merge)[i].type)); for (uint32_t i = 0; i < std::min(arity, inserted_value_count); i++) {
} if (stack_base[i].type == kWasmBottom) {
// {drop_values} are about to be dropped anyway, so we can forget their stack_base[i].type = (*merge)[i].type;
// previous types, but we do have to maintain the correct stack height. }
for (uint32_t i = 0; i < drop_values; i++) { }
Push(UnreachableValue(this->pc_));
} }
} }
return this->ok(); return this->ok();
......
...@@ -1099,8 +1099,11 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) { ...@@ -1099,8 +1099,11 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
byte array_index = builder.AddArray(kWasmI32, true); byte array_index = builder.AddArray(kWasmI32, true);
ValueType struct_type = ValueType::Ref(struct_index, kNonNullable); ValueType struct_type = ValueType::Ref(struct_index, kNonNullable);
ValueType struct_type_null = ValueType::Ref(struct_index, kNullable);
FunctionSig sig_v_s(0, 1, &struct_type); FunctionSig sig_v_s(0, 1, &struct_type);
byte struct_consumer = builder.AddFunction(&sig_v_s); byte struct_consumer = builder.AddFunction(&sig_v_s);
byte struct_consumer2 = builder.AddFunction(
FunctionSig::Build(zone(), {kWasmI32}, {struct_type, struct_type}));
ExpectValidates(sigs.i_v(), {WASM_UNREACHABLE, kExprRefIsNull}); ExpectValidates(sigs.i_v(), {WASM_UNREACHABLE, kExprRefIsNull});
ExpectValidates(sigs.v_v(), {WASM_UNREACHABLE, kExprRefAsNonNull, kExprDrop}); ExpectValidates(sigs.v_v(), {WASM_UNREACHABLE, kExprRefAsNonNull, kExprDrop});
...@@ -1174,15 +1177,24 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) { ...@@ -1174,15 +1177,24 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
ExpectValidates(FunctionSig::Build(zone(), {kWasmDataRef}, {}), ExpectValidates(FunctionSig::Build(zone(), {kWasmDataRef}, {}),
{WASM_UNREACHABLE, WASM_GC_OP(kExprRefAsData)}); {WASM_UNREACHABLE, WASM_GC_OP(kExprRefAsData)});
ExpectValidates( ExpectValidates(FunctionSig::Build(zone(), {}, {struct_type_null}),
FunctionSig::Build(zone(), {}, {ValueType::Ref(struct_index, kNullable)}), {WASM_UNREACHABLE, WASM_LOCAL_GET(0), kExprBrOnNull, 0,
{WASM_UNREACHABLE, WASM_LOCAL_GET(0), kExprBrOnNull, 0, kExprCallFunction, kExprCallFunction, struct_consumer});
struct_consumer});
ExpectFailure( ExpectFailure(
sigs.v_v(), {WASM_UNREACHABLE, WASM_I32V(42), kExprBrOnNull, 0}, sigs.v_v(), {WASM_UNREACHABLE, WASM_I32V(42), kExprBrOnNull, 0},
kAppendEnd, kAppendEnd,
"br_on_null[0] expected object reference, found i32.const of type i32"); "br_on_null[0] expected object reference, found i32.const of type i32");
// This tests for a bug where {TypeCheckStackAgainstMerge} did not insert
// unreachable values into the stack correctly.
ExpectValidates(FunctionSig::Build(zone(), {kWasmI32}, {struct_type_null}),
{WASM_BLOCK_R(struct_type_null, kExprUnreachable, // --
kExprLocalGet, 0, kExprRefAsNonNull, // --
kExprLocalGet, 0, kExprBrOnNull, 0, // --
kExprCallFunction, struct_consumer2, // --
kExprBr, 1),
kExprDrop, WASM_I32V(1)});
} }
TEST_F(FunctionBodyDecoderTest, If1) { TEST_F(FunctionBodyDecoderTest, If1) {
......
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