[wasm-gc] read_heap_type should check if index is in module bounds
read_heap_type did not have knowledge of the module for which the heap type was being decoded. As a result, callers of read_heap_type (or read_value_type, which in turn calls read_heap_type) had to check after the fact that a decoded indexed type (ref, ref null, or rtt) references a type index within the module's bounds. This was not done consistently, and was missing (at least) in DecodeLocals. To avoid such problems in the future, this CL refactors read_heap_type to accept a module and check the decoded index against it. Changes: - Add WasmModule argument to read_heap_type. Do so accordingly to all its transitive callers (read_value_type, immediate arguments, DecodeLocalDecls, DecodeValue/HeapType in unittests). - Add index check to read_heap_type and emit an error for an out-of-bounds index. - Remove all other now-redundant index validations. Replace them with decoder->ok() if needed (since read_heap_type will now emit an error). - Fix error message in Validate for BlockTypeImmediate. - In DecodeLocalDecls in unittests, pass an empty module to DecodeLocalDecls in the main code. - Add a unit test with an invalid index in local type declarations. Bug: v8:9495 Change-Id: I4ed1204847db80f78b6ae85fa40d300cd2456295 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2569757 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/master@{#71572}
This commit is contained in:
parent
2bc979aa0a
commit
0396b732e7
@ -195,9 +195,12 @@ V8_INLINE WasmFeature feature_for_heap_type(HeapType heap_type) {
|
||||
}
|
||||
}
|
||||
|
||||
// If {module} is not null, the read index will be checked against the module's
|
||||
// type capacity.
|
||||
template <Decoder::ValidateFlag validate>
|
||||
HeapType read_heap_type(Decoder* decoder, const byte* pc,
|
||||
uint32_t* const length, const WasmFeatures& enabled) {
|
||||
uint32_t* const length, const WasmModule* module,
|
||||
const WasmFeatures& enabled) {
|
||||
int64_t heap_index = decoder->read_i33v<validate>(pc, length, "heap type");
|
||||
if (heap_index < 0) {
|
||||
int64_t min_1_byte_leb128 = -64;
|
||||
@ -248,6 +251,12 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
|
||||
type_index, kV8MaxWasmTypes);
|
||||
return HeapType(HeapType::kBottom);
|
||||
}
|
||||
// We use capacity over size so this works mid-DecodeTypeSection.
|
||||
if (!VALIDATE(module == nullptr || type_index < module->types.capacity())) {
|
||||
DecodeError<validate>(decoder, pc, "Type index %u is out of bounds",
|
||||
type_index);
|
||||
return HeapType(HeapType::kBottom);
|
||||
}
|
||||
return HeapType(type_index);
|
||||
}
|
||||
}
|
||||
@ -259,7 +268,8 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
|
||||
// kNoValidate.
|
||||
template <Decoder::ValidateFlag validate>
|
||||
ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
uint32_t* const length, const WasmFeatures& enabled) {
|
||||
uint32_t* const length, const WasmModule* module,
|
||||
const WasmFeatures& enabled) {
|
||||
*length = 1;
|
||||
byte val = decoder->read_u8<validate>(pc, "value type opcode");
|
||||
if (decoder->failed()) {
|
||||
@ -306,7 +316,7 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
return kWasmBottom;
|
||||
}
|
||||
HeapType heap_type =
|
||||
read_heap_type<validate>(decoder, pc + 1, length, enabled);
|
||||
read_heap_type<validate>(decoder, pc + 1, length, module, enabled);
|
||||
*length += 1;
|
||||
return heap_type.is_bottom() ? kWasmBottom
|
||||
: ValueType::Ref(heap_type, nullability);
|
||||
@ -329,8 +339,8 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
return kWasmBottom;
|
||||
}
|
||||
uint32_t heap_type_length;
|
||||
HeapType heap_type = read_heap_type<validate>(decoder, pc + *length,
|
||||
&heap_type_length, enabled);
|
||||
HeapType heap_type = read_heap_type<validate>(
|
||||
decoder, pc + *length, &heap_type_length, module, enabled);
|
||||
*length += heap_type_length;
|
||||
return heap_type.is_bottom() ? kWasmBottom
|
||||
: ValueType::Rtt(heap_type, depth);
|
||||
@ -445,7 +455,7 @@ struct SelectTypeImmediate {
|
||||
ValueType type;
|
||||
|
||||
inline SelectTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||
const byte* pc) {
|
||||
const byte* pc, const WasmModule* module) {
|
||||
uint8_t num_types =
|
||||
decoder->read_u32v<validate>(pc, &length, "number of select types");
|
||||
if (!VALIDATE(num_types == 1)) {
|
||||
@ -455,8 +465,8 @@ struct SelectTypeImmediate {
|
||||
return;
|
||||
}
|
||||
uint32_t type_length;
|
||||
type = value_type_reader::read_value_type<validate>(decoder, pc + length,
|
||||
&type_length, enabled);
|
||||
type = value_type_reader::read_value_type<validate>(
|
||||
decoder, pc + length, &type_length, module, enabled);
|
||||
length += type_length;
|
||||
}
|
||||
};
|
||||
@ -469,7 +479,7 @@ struct BlockTypeImmediate {
|
||||
const FunctionSig* sig = nullptr;
|
||||
|
||||
inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||
const byte* pc) {
|
||||
const byte* pc, const WasmModule* module) {
|
||||
int64_t block_type =
|
||||
decoder->read_i33v<validate>(pc, &length, "block type");
|
||||
if (block_type < 0) {
|
||||
@ -483,7 +493,7 @@ struct BlockTypeImmediate {
|
||||
}
|
||||
if (static_cast<ValueTypeCode>(block_type & 0x7F) == kVoidCode) return;
|
||||
type = value_type_reader::read_value_type<validate>(decoder, pc, &length,
|
||||
enabled);
|
||||
module, enabled);
|
||||
} else {
|
||||
if (!VALIDATE(enabled.has_mv())) {
|
||||
DecodeError<validate>(decoder, pc,
|
||||
@ -826,9 +836,9 @@ struct HeapTypeImmediate {
|
||||
uint32_t length = 1;
|
||||
HeapType type = HeapType(HeapType::kBottom);
|
||||
inline HeapTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||
const byte* pc) {
|
||||
const byte* pc, const WasmModule* module) {
|
||||
type = value_type_reader::read_heap_type<validate>(decoder, pc, &length,
|
||||
enabled);
|
||||
module, enabled);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1172,7 +1182,7 @@ class WasmDecoder : public Decoder {
|
||||
*total_length += length;
|
||||
|
||||
ValueType type = value_type_reader::read_value_type<validate>(
|
||||
this, pc + *total_length, &length, enabled_);
|
||||
this, pc + *total_length, &length, this->module_, enabled_);
|
||||
if (!VALIDATE(type != kWasmBottom)) return -1;
|
||||
*total_length += length;
|
||||
total_count += count;
|
||||
@ -1479,8 +1489,8 @@ class WasmDecoder : public Decoder {
|
||||
|
||||
inline bool Validate(const byte* pc, BlockTypeImmediate<validate>& imm) {
|
||||
if (!Complete(imm)) {
|
||||
DecodeError(pc, "block type index %u out of bounds (%zu types)",
|
||||
imm.sig_index, module_->types.size());
|
||||
DecodeError(pc, "block type index %u is not a signature definition",
|
||||
imm.sig_index);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1578,19 +1588,6 @@ class WasmDecoder : public Decoder {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Validate(const byte* pc, HeapTypeImmediate<validate>& imm) {
|
||||
if (!VALIDATE(!imm.type.is_bottom())) {
|
||||
DecodeError(pc, "invalid heap type");
|
||||
return false;
|
||||
}
|
||||
if (!VALIDATE(imm.type.is_generic() ||
|
||||
module_->has_type(imm.type.ref_index()))) {
|
||||
DecodeError(pc, "Type index %u is out of bounds", imm.type.ref_index());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the length of the opcode under {pc}.
|
||||
static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) {
|
||||
WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
|
||||
@ -1611,7 +1608,8 @@ class WasmDecoder : public Decoder {
|
||||
case kExprIf:
|
||||
case kExprLoop:
|
||||
case kExprBlock: {
|
||||
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
|
||||
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
|
||||
nullptr);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprBr:
|
||||
@ -1637,7 +1635,8 @@ class WasmDecoder : public Decoder {
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprLet: {
|
||||
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
|
||||
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
|
||||
nullptr);
|
||||
uint32_t locals_length;
|
||||
int new_locals_count = decoder->DecodeLocals(
|
||||
pc + 1 + imm.length, &locals_length, base::Optional<uint32_t>());
|
||||
@ -1662,7 +1661,8 @@ class WasmDecoder : public Decoder {
|
||||
case kExprSelect:
|
||||
return 1;
|
||||
case kExprSelectWithType: {
|
||||
SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
|
||||
SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
|
||||
nullptr);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprLocalGet:
|
||||
@ -1694,7 +1694,8 @@ class WasmDecoder : public Decoder {
|
||||
case kExprF64Const:
|
||||
return 9;
|
||||
case kExprRefNull: {
|
||||
HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
|
||||
HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1,
|
||||
nullptr);
|
||||
return 1 + imm.length;
|
||||
}
|
||||
case kExprRefIsNull: {
|
||||
@ -1881,7 +1882,7 @@ class WasmDecoder : public Decoder {
|
||||
// TODO(7748): Account for rtt.sub's additional immediates if
|
||||
// they stick.
|
||||
HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder,
|
||||
pc + length);
|
||||
pc + length, nullptr);
|
||||
return length + imm.length;
|
||||
}
|
||||
case kExprI31New:
|
||||
@ -1891,9 +1892,9 @@ class WasmDecoder : public Decoder {
|
||||
case kExprRefTest:
|
||||
case kExprRefCast: {
|
||||
HeapTypeImmediate<validate> ht1(WasmFeatures::All(), decoder,
|
||||
pc + length);
|
||||
pc + length, nullptr);
|
||||
HeapTypeImmediate<validate> ht2(WasmFeatures::All(), decoder,
|
||||
pc + length + ht1.length);
|
||||
pc + length + ht1.length, nullptr);
|
||||
return length + ht1.length + ht2.length;
|
||||
}
|
||||
default:
|
||||
@ -2371,7 +2372,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
#undef BUILD_SIMPLE_OPCODE
|
||||
|
||||
DECODE(Block) {
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PopArgs(imm.sig);
|
||||
Control* block = PushControl(kControlBlock);
|
||||
@ -2401,7 +2403,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
|
||||
DECODE(Try) {
|
||||
CHECK_PROTOTYPE_OPCODE(eh);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PopArgs(imm.sig);
|
||||
Control* try_block = PushControl(kControlTry);
|
||||
@ -2501,7 +2504,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
|
||||
DECODE(Let) {
|
||||
CHECK_PROTOTYPE_OPCODE(typed_funcref);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
// Temporarily add the let-defined values to the beginning of the function
|
||||
// locals.
|
||||
@ -2524,7 +2528,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
|
||||
DECODE(Loop) {
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
ArgVector args = PopArgs(imm.sig);
|
||||
Control* block = PushControl(kControlLoop);
|
||||
@ -2535,7 +2540,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
|
||||
DECODE(If) {
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
Value cond = Pop(0, kWasmI32);
|
||||
ArgVector args = PopArgs(imm.sig);
|
||||
@ -2631,7 +2637,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
|
||||
DECODE(SelectWithType) {
|
||||
CHECK_PROTOTYPE_OPCODE(reftypes);
|
||||
SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
SelectTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (this->failed()) return 0;
|
||||
Value cond = Pop(2, kWasmI32);
|
||||
Value fval = Pop(1, imm.type);
|
||||
@ -2773,8 +2780,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
|
||||
DECODE(RefNull) {
|
||||
CHECK_PROTOTYPE_OPCODE(reftypes);
|
||||
HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
|
||||
if (!this->Validate(this->pc_ + 1, imm)) return 0;
|
||||
HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1,
|
||||
this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
ValueType type = ValueType::Ref(imm.type, kNullable);
|
||||
Value* value = Push(type);
|
||||
CALL_INTERFACE_IF_REACHABLE(RefNull, type, value);
|
||||
@ -3937,9 +3945,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
return opcode_length;
|
||||
}
|
||||
case kExprRttCanon: {
|
||||
HeapTypeImmediate<validate> imm(this->enabled_, this,
|
||||
this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
HeapTypeImmediate<validate> imm(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
Value* value =
|
||||
Push(ValueType::Rtt(imm.type, imm.type == HeapType::kAny ? 0 : 1));
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
|
||||
@ -3952,9 +3960,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
// If these immediates don't get dropped (in the spirit of
|
||||
// https://github.com/WebAssembly/function-references/pull/31 ),
|
||||
// implement them here.
|
||||
HeapTypeImmediate<validate> imm(this->enabled_, this,
|
||||
this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
HeapTypeImmediate<validate> imm(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
Value parent = Pop(0);
|
||||
if (parent.type.is_bottom()) {
|
||||
Push(kWasmBottom);
|
||||
@ -3986,14 +3994,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
case kExprRefTest: {
|
||||
// "Tests whether {obj}'s runtime type is a runtime subtype of {rtt}."
|
||||
HeapTypeImmediate<validate> obj_type(this->enabled_, this,
|
||||
this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, obj_type)) return 0;
|
||||
HeapTypeImmediate<validate> obj_type(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
int len = opcode_length + obj_type.length;
|
||||
HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
|
||||
this->pc_ + len);
|
||||
if (!this->Validate(this->pc_ + len, rtt_type)) return 0;
|
||||
this->pc_ + len, this->module_);
|
||||
len += rtt_type.length;
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
|
||||
// The static type of {obj} must be a supertype of the {rtt}'s type.
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
|
||||
ValueType::Ref(obj_type.type, kNonNullable),
|
||||
@ -4017,14 +4025,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
return len;
|
||||
}
|
||||
case kExprRefCast: {
|
||||
HeapTypeImmediate<validate> obj_type(this->enabled_, this,
|
||||
this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, obj_type)) return 0;
|
||||
HeapTypeImmediate<validate> obj_type(
|
||||
this->enabled_, this, this->pc_ + opcode_length, this->module_);
|
||||
int len = opcode_length + obj_type.length;
|
||||
HeapTypeImmediate<validate> rtt_type(this->enabled_, this,
|
||||
this->pc_ + len);
|
||||
if (!this->Validate(this->pc_ + len, rtt_type)) return 0;
|
||||
this->pc_ + len, this->module_);
|
||||
len += rtt_type.length;
|
||||
if (!VALIDATE(this->ok())) return 0;
|
||||
|
||||
if (!VALIDATE(IsSubtypeOf(ValueType::Ref(rtt_type.type, kNonNullable),
|
||||
ValueType::Ref(obj_type.type, kNonNullable),
|
||||
this->module_))) {
|
||||
|
@ -20,11 +20,12 @@ namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
|
||||
const byte* start, const byte* end) {
|
||||
const WasmModule* module, const byte* start,
|
||||
const byte* end) {
|
||||
WasmFeatures no_features = WasmFeatures::None();
|
||||
Zone* zone = decls->type_list.get_allocator().zone();
|
||||
WasmDecoder<Decoder::kFullValidation> decoder(
|
||||
zone, nullptr, enabled, &no_features, nullptr, start, end, 0);
|
||||
zone, module, enabled, &no_features, nullptr, start, end, 0);
|
||||
uint32_t length;
|
||||
if (decoder.DecodeLocals(decoder.pc(), &length, 0) < 0) {
|
||||
decls->encoded_size = 0;
|
||||
@ -42,7 +43,7 @@ BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
|
||||
BodyLocalDecls* decls)
|
||||
: Decoder(start, end) {
|
||||
if (decls != nullptr) {
|
||||
if (DecodeLocalDecls(WasmFeatures::All(), decls, start, end)) {
|
||||
if (DecodeLocalDecls(WasmFeatures::All(), decls, nullptr, start, end)) {
|
||||
pc_ += decls->encoded_size;
|
||||
if (pc_ > end_) pc_ = end_;
|
||||
}
|
||||
@ -244,7 +245,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
||||
case kExprBlock:
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(), &i,
|
||||
i.pc() + 1);
|
||||
i.pc() + 1, module);
|
||||
os << " @" << i.pc_offset();
|
||||
if (decoder.Complete(imm)) {
|
||||
for (uint32_t i = 0; i < imm.out_arity(); i++) {
|
||||
|
@ -67,6 +67,7 @@ struct BodyLocalDecls {
|
||||
|
||||
V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled,
|
||||
BodyLocalDecls* decls,
|
||||
const WasmModule* module,
|
||||
const byte* start, const byte* end);
|
||||
|
||||
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(
|
||||
|
@ -1648,22 +1648,6 @@ class ModuleDecoderImpl : public Decoder {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(manoskouk): This is copy-modified from function-body-decoder-impl.h.
|
||||
// We should find a way to share this code.
|
||||
V8_INLINE bool Validate(const byte* pc,
|
||||
HeapTypeImmediate<kFullValidation>& imm) {
|
||||
if (V8_UNLIKELY(imm.type.is_bottom())) {
|
||||
error(pc, "invalid heap type");
|
||||
return false;
|
||||
}
|
||||
if (V8_UNLIKELY(!(imm.type.is_generic() ||
|
||||
module_->has_type(imm.type.ref_index())))) {
|
||||
errorf(pc, "Type index %u is out of bounds", imm.type.ref_index());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected,
|
||||
size_t current_global_index) {
|
||||
constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
|
||||
@ -1735,10 +1719,10 @@ class ModuleDecoderImpl : public Decoder {
|
||||
kExprRefNull);
|
||||
return {};
|
||||
}
|
||||
HeapTypeImmediate<Decoder::kFullValidation> imm(enabled_features_,
|
||||
this, pc() + 1);
|
||||
HeapTypeImmediate<Decoder::kFullValidation> imm(
|
||||
enabled_features_, this, pc() + 1, module_.get());
|
||||
if (V8_UNLIKELY(failed())) return {};
|
||||
len = 1 + imm.length;
|
||||
if (!Validate(pc() + 1, imm)) return {};
|
||||
stack.push_back(
|
||||
WasmInitExpr::RefNullConst(imm.type.representation()));
|
||||
break;
|
||||
@ -1786,19 +1770,19 @@ class ModuleDecoderImpl : public Decoder {
|
||||
opcode = read_prefixed_opcode<validate>(pc(), &len);
|
||||
switch (opcode) {
|
||||
case kExprRttCanon: {
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this,
|
||||
pc() + 2);
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this, pc() + 2,
|
||||
module_.get());
|
||||
if (V8_UNLIKELY(failed())) return {};
|
||||
len += imm.length;
|
||||
if (!Validate(pc() + len, imm)) return {};
|
||||
stack.push_back(
|
||||
WasmInitExpr::RttCanon(imm.type.representation()));
|
||||
break;
|
||||
}
|
||||
case kExprRttSub: {
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this,
|
||||
pc() + 2);
|
||||
HeapTypeImmediate<validate> imm(enabled_features_, this, pc() + 2,
|
||||
module_.get());
|
||||
if (V8_UNLIKELY(failed())) return {};
|
||||
len += imm.length;
|
||||
if (!Validate(pc() + len, imm)) return {};
|
||||
if (stack.empty()) {
|
||||
error(pc(), "calling rtt.sub without arguments");
|
||||
return {};
|
||||
@ -1870,13 +1854,8 @@ class ModuleDecoderImpl : public Decoder {
|
||||
ValueType consume_value_type() {
|
||||
uint32_t type_length;
|
||||
ValueType result = value_type_reader::read_value_type<kFullValidation>(
|
||||
this, this->pc(), &type_length,
|
||||
this, this->pc(), &type_length, module_.get(),
|
||||
origin_ == kWasmOrigin ? enabled_features_ : WasmFeatures::None());
|
||||
// We use capacity() over size() so this function works
|
||||
// mid-DecodeTypeSection.
|
||||
if (result.has_index() && result.ref_index() >= module_->types.capacity()) {
|
||||
errorf(pc(), "Type index %u is out of bounds", result.ref_index());
|
||||
}
|
||||
consume_bytes(type_length, "value type");
|
||||
return result;
|
||||
}
|
||||
@ -2166,7 +2145,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
switch (opcode) {
|
||||
case kExprRefNull: {
|
||||
HeapTypeImmediate<kFullValidation> imm(WasmFeatures::All(), this,
|
||||
this->pc());
|
||||
this->pc(), module_.get());
|
||||
consume_bytes(imm.length, "ref.null immediate");
|
||||
index = WasmElemSegment::kNullIndex;
|
||||
break;
|
||||
|
@ -790,8 +790,8 @@ class SideTable : public ZoneObject {
|
||||
case kExprBlock:
|
||||
case kExprLoop: {
|
||||
bool is_loop = opcode == kExprLoop;
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(),
|
||||
&i, i.pc() + 1);
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &i, i.pc() + 1, module);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -812,8 +812,8 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprIf: {
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(),
|
||||
&i, i.pc() + 1);
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &i, i.pc() + 1, module);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -852,8 +852,8 @@ class SideTable : public ZoneObject {
|
||||
break;
|
||||
}
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(),
|
||||
&i, i.pc() + 1);
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &i, i.pc() + 1, module);
|
||||
if (imm.type == kWasmBottom) {
|
||||
imm.sig = module->signature(imm.sig_index);
|
||||
}
|
||||
@ -3262,13 +3262,13 @@ class WasmInterpreterInternals {
|
||||
case kExprLoop:
|
||||
case kExprTry: {
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1), module());
|
||||
len = 1 + imm.length;
|
||||
break;
|
||||
}
|
||||
case kExprIf: {
|
||||
BlockTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1), module());
|
||||
WasmValue cond = Pop();
|
||||
bool is_true = cond.to<uint32_t>() != 0;
|
||||
if (is_true) {
|
||||
@ -3328,7 +3328,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprSelectWithType: {
|
||||
SelectTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1), module());
|
||||
len = 1 + imm.length;
|
||||
V8_FALLTHROUGH;
|
||||
}
|
||||
@ -3417,7 +3417,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case kExprRefNull: {
|
||||
HeapTypeImmediate<Decoder::kNoValidation> imm(
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1));
|
||||
WasmFeatures::All(), &decoder, code->at(pc + 1), module());
|
||||
len = 1 + imm.length;
|
||||
Push(WasmValue(isolate_->factory()->null_value()));
|
||||
break;
|
||||
|
@ -269,7 +269,7 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
|
||||
// Add locals.
|
||||
BodyLocalDecls decls(&tmp_zone);
|
||||
DecodeLocalDecls(enabled_features, &decls, func_code.begin(),
|
||||
DecodeLocalDecls(enabled_features, &decls, module, func_code.begin(),
|
||||
func_code.end());
|
||||
if (!decls.type_list.empty()) {
|
||||
os << " ";
|
||||
|
@ -4663,18 +4663,20 @@ TEST_F(WasmOpcodeLengthTest, PrefixedOpcodesLEB) {
|
||||
|
||||
class TypeReaderTest : public TestWithZone {
|
||||
public:
|
||||
ValueType DecodeValueType(const byte* start, const byte* end) {
|
||||
ValueType DecodeValueType(const byte* start, const byte* end,
|
||||
const WasmModule* module) {
|
||||
Decoder decoder(start, end);
|
||||
uint32_t length;
|
||||
return value_type_reader::read_value_type<Decoder::kFullValidation>(
|
||||
&decoder, start, &length, enabled_features_);
|
||||
&decoder, start, &length, module, enabled_features_);
|
||||
}
|
||||
|
||||
HeapType DecodeHeapType(const byte* start, const byte* end) {
|
||||
HeapType DecodeHeapType(const byte* start, const byte* end,
|
||||
const WasmModule* module) {
|
||||
Decoder decoder(start, end);
|
||||
uint32_t length;
|
||||
return value_type_reader::read_heap_type<Decoder::kFullValidation>(
|
||||
&decoder, start, &length, enabled_features_);
|
||||
&decoder, start, &length, module, enabled_features_);
|
||||
}
|
||||
|
||||
// This variable is modified by WASM_FEATURE_SCOPE.
|
||||
@ -4692,34 +4694,34 @@ TEST_F(TypeReaderTest, HeapTypeDecodingTest) {
|
||||
// 1- to 5-byte representation of kFuncRefCode.
|
||||
{
|
||||
const byte data[] = {kFuncRefCode};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_TRUE(result == heap_func);
|
||||
}
|
||||
{
|
||||
const byte data[] = {kFuncRefCode | 0x80, 0x7F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_func);
|
||||
}
|
||||
{
|
||||
const byte data[] = {kFuncRefCode | 0x80, 0xFF, 0x7F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_func);
|
||||
}
|
||||
{
|
||||
const byte data[] = {kFuncRefCode | 0x80, 0xFF, 0xFF, 0x7F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_func);
|
||||
}
|
||||
{
|
||||
const byte data[] = {kFuncRefCode | 0x80, 0xFF, 0xFF, 0xFF, 0x7F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_func);
|
||||
}
|
||||
|
||||
{
|
||||
// Some negative number.
|
||||
const byte data[] = {0xB4, 0x7F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_bottom);
|
||||
}
|
||||
|
||||
@ -4728,7 +4730,7 @@ TEST_F(TypeReaderTest, HeapTypeDecodingTest) {
|
||||
// range. This should therefore NOT be decoded as HeapType::kFunc and
|
||||
// instead fail.
|
||||
const byte data[] = {kFuncRefCode | 0x80, 0x6F};
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data));
|
||||
HeapType result = DecodeHeapType(data, data + sizeof(data), nullptr);
|
||||
EXPECT_EQ(result, heap_bottom);
|
||||
}
|
||||
}
|
||||
@ -4750,7 +4752,9 @@ class LocalDeclDecoderTest : public TestWithZone {
|
||||
|
||||
bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start,
|
||||
const byte* end) {
|
||||
return i::wasm::DecodeLocalDecls(enabled_features_, decls, start, end);
|
||||
WasmModule module;
|
||||
return i::wasm::DecodeLocalDecls(enabled_features_, decls, &module, start,
|
||||
end);
|
||||
}
|
||||
};
|
||||
|
||||
@ -4877,6 +4881,20 @@ TEST_F(LocalDeclDecoderTest, ExnRef) {
|
||||
EXPECT_EQ(type, map[0]);
|
||||
}
|
||||
|
||||
TEST_F(LocalDeclDecoderTest, InvalidTypeIndex) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
|
||||
const byte* data = nullptr;
|
||||
const byte* end = nullptr;
|
||||
LocalDeclEncoder local_decls(zone());
|
||||
|
||||
local_decls.AddLocals(1, ValueType::Ref(0, kNullable));
|
||||
BodyLocalDecls decls(zone());
|
||||
bool result = DecodeLocalDecls(&decls, data, end);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
class BytecodeIteratorTest : public TestWithZone {};
|
||||
|
||||
TEST_F(BytecodeIteratorTest, SimpleForeach) {
|
||||
|
Loading…
Reference in New Issue
Block a user