diff --git a/src/wasm/encoder.cc b/src/wasm/encoder.cc index 2128505ac7..3e30731c38 100644 --- a/src/wasm/encoder.cc +++ b/src/wasm/encoder.cc @@ -59,16 +59,16 @@ void EmitVarInt(byte** b, size_t val) { // We generate a large varint which we then fixup later when the size is known. // // TODO(jfb) Not strictly necessary since sizes are calculated ahead of time. -const size_t padded_varint = 5; +const size_t kPaddedVarintSize = 5; void FixupSection(byte* start, byte* end) { // Same as LEBHelper::write_u32v, but fixed-width with zeroes in the MSBs. - size_t val = end - start - padded_varint; + size_t val = end - start - kPaddedVarintSize; TRACE(" fixup %u\n", (unsigned)val); - for (size_t pos = 0; pos != padded_varint; ++pos) { + for (size_t pos = 0; pos != kPaddedVarintSize; ++pos) { size_t next = val >> 7; byte out = static_cast(val & 0x7f); - if (pos != padded_varint - 1) { + if (pos != kPaddedVarintSize - 1) { *(start++) = 0x80 | out; val = next; } else { @@ -80,15 +80,18 @@ void FixupSection(byte* start, byte* end) { // Returns the start of the section, where the section VarInt size is. byte* EmitSection(WasmSection::Code code, byte** b) { + // Emit a placeholder for the length. byte* start = *b; - const char* name = WasmSection::getName(code); - size_t length = WasmSection::getNameLength(code); - TRACE("emit section: %s\n", name); - for (size_t padding = 0; padding != padded_varint; ++padding) { + for (size_t padding = 0; padding != kPaddedVarintSize; ++padding) { EmitUint8(b, 0xff); // Will get fixed up later. } + // Emit the section name. + const char* name = WasmSection::getName(code); + TRACE("emit section: %s\n", name); + size_t length = WasmSection::getNameLength(code); EmitVarInt(b, length); // Section name string size. for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]); + return start; } } // namespace @@ -548,7 +551,7 @@ struct Sizes { } void AddSection(WasmSection::Code code, size_t other_size) { - Add(padded_varint + + Add(kPaddedVarintSize + LEBHelper::sizeof_u32v(WasmSection::getNameLength(code)) + WasmSection::getNameLength(code), 0); @@ -561,11 +564,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { sizes.Add(2 * sizeof(uint32_t), 0); // header - sizes.AddSection(WasmSection::Code::Memory, 0); - sizes.Add(kDeclMemorySize, 0); - TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size, - (unsigned)sizes.body_size); - if (globals_.size() > 0) { sizes.AddSection(WasmSection::Code::Globals, globals_.size()); /* These globals never have names, so are always 3 bytes. */ @@ -595,6 +593,21 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { (unsigned)sizes.body_size); } + if (indirect_functions_.size() > 0) { + sizes.AddSection(WasmSection::Code::FunctionTable, + indirect_functions_.size()); + for (auto function_index : indirect_functions_) { + sizes.Add(LEBHelper::sizeof_u32v(function_index), 0); + } + TRACE("Size after indirect functions: %u, %u\n", + (unsigned)sizes.header_size, (unsigned)sizes.body_size); + } + + sizes.AddSection(WasmSection::Code::Memory, 0); + sizes.Add(kDeclMemorySize, 0); + TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size, + (unsigned)sizes.body_size); + if (start_function_index_ >= 0) { sizes.AddSection(WasmSection::Code::StartFunction, 0); sizes.Add(LEBHelper::sizeof_u32v(start_function_index_), 0); @@ -611,16 +624,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { (unsigned)sizes.body_size); } - if (indirect_functions_.size() > 0) { - sizes.AddSection(WasmSection::Code::FunctionTable, - indirect_functions_.size()); - for (auto function_index : indirect_functions_) { - sizes.Add(LEBHelper::sizeof_u32v(function_index), 0); - } - TRACE("Size after indirect functions: %u, %u\n", - (unsigned)sizes.header_size, (unsigned)sizes.body_size); - } - if (sizes.body_size > 0) { sizes.AddSection(WasmSection::Code::End, 0); TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size, @@ -637,16 +640,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { EmitUint32(&header, kWasmMagic); EmitUint32(&header, kWasmVersion); - // -- emit memory declaration ------------------------------------------------ - { - byte* section = EmitSection(WasmSection::Code::Memory, &header); - EmitVarInt(&header, 16); // min memory size - EmitVarInt(&header, 16); // max memory size - EmitUint8(&header, 0); // memory export - static_assert(kDeclMemorySize == 3, "memory size must match emit above"); - FixupSection(section, header); - } - // -- emit globals ----------------------------------------------------------- if (globals_.size() > 0) { byte* section = EmitSection(WasmSection::Code::Globals, &header); @@ -690,6 +683,27 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { FixupSection(section, header); } + // -- emit function table ---------------------------------------------------- + if (indirect_functions_.size() > 0) { + byte* section = EmitSection(WasmSection::Code::FunctionTable, &header); + EmitVarInt(&header, indirect_functions_.size()); + + for (auto index : indirect_functions_) { + EmitVarInt(&header, index); + } + FixupSection(section, header); + } + + // -- emit memory declaration ------------------------------------------------ + { + byte* section = EmitSection(WasmSection::Code::Memory, &header); + EmitVarInt(&header, 16); // min memory size + EmitVarInt(&header, 16); // max memory size + EmitUint8(&header, 0); // memory export + static_assert(kDeclMemorySize == 3, "memory size must match emit above"); + FixupSection(section, header); + } + // -- emit start function index ---------------------------------------------- if (start_function_index_ >= 0) { byte* section = EmitSection(WasmSection::Code::StartFunction, &header); @@ -708,17 +722,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { FixupSection(section, header); } - // -- emit function table ---------------------------------------------------- - if (indirect_functions_.size() > 0) { - byte* section = EmitSection(WasmSection::Code::FunctionTable, &header); - EmitVarInt(&header, indirect_functions_.size()); - - for (auto index : indirect_functions_) { - EmitVarInt(&header, index); - } - FixupSection(section, header); - } - if (sizes.body_size > 0) { byte* section = EmitSection(WasmSection::Code::End, &header); FixupSection(section, header); diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc index f09e4ea77b..25ce7b6cd7 100644 --- a/src/wasm/module-decoder.cc +++ b/src/wasm/module-decoder.cc @@ -25,7 +25,6 @@ namespace wasm { #define TRACE(...) #endif - // The main logic for decoding the bytes of a module. class ModuleDecoder : public Decoder { public: @@ -79,9 +78,8 @@ class ModuleDecoder : public Decoder { module->mem_external = false; module->origin = origin_; - bool sections[(size_t)WasmSection::Code::Max] = {false}; - const byte* pos = pc_; + int current_order = 0; uint32_t magic_word = consume_u32("wasm magic"); #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff if (magic_word != kWasmMagic) { @@ -109,33 +107,37 @@ class ModuleDecoder : public Decoder { TRACE("DecodeSection\n"); pos = pc_; - int length; - uint32_t section_length = consume_u32v(&length, "section size"); - - int section_string_leb_length = 0; - uint32_t section_string_length = 0; - WasmSection::Code section = consume_section_name( - §ion_string_leb_length, §ion_string_length); - uint32_t string_and_leb_length = - section_string_leb_length + section_string_length; - if (string_and_leb_length > section_length) { - error(pos, pos, - "section string of size %u longer than total section bytes %u", - string_and_leb_length, section_length); + // Read and check the section size. + int section_leb_length = 0; + uint32_t section_length = + consume_u32v(§ion_leb_length, "section length"); + if (!checkAvailable(section_length)) { + // The section would extend beyond the end of the module. break; } + const byte* section_start = pc_; + const byte* expected_section_end = pc_ + section_length; - if (section == WasmSection::Code::Max) { - // Skip unknown section. - uint32_t skip = section_length - string_and_leb_length; - TRACE("skipping %u bytes from unknown section\n", skip); - consume_bytes(skip); - continue; + // Read the section name. + int string_leb_length = 0; + uint32_t string_length = + consume_u32v(&string_leb_length, "section name length"); + const byte* section_name_start = pc_; + consume_bytes(string_length); + if (failed()) { + TRACE("Section name of length %u couldn't be read\n", string_length); + break; + } + if (pc_ > expected_section_end) { + error(section_name_start, pc_, + "section name string %u longer than total section bytes %u", + string_length, section_length); } - // Each section should appear at most once. - CheckForPreviousSection(sections, section, false); - sections[(size_t)section] = true; + WasmSection::Code section = + WasmSection::lookup(section_name_start, string_length); + + current_order = CheckSectionOrder(current_order, section); switch (section) { case WasmSection::Code::End: @@ -163,9 +165,6 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::FunctionSignatures: { - // Functions require a signature table first. - CheckForPreviousSection(sections, WasmSection::Code::Signatures, - true); int length; uint32_t functions_count = consume_u32v(&length, "functions count"); module->functions.reserve(SafeReserve(functions_count)); @@ -178,9 +177,6 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::FunctionBodies: { - // Function bodies should follow signatures. - CheckForPreviousSection(sections, - WasmSection::Code::FunctionSignatures, true); int length; const byte* pos = pc_; uint32_t functions_count = consume_u32v(&length, "functions count"); @@ -207,9 +203,6 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::Functions: { - // Functions require a signature table first. - CheckForPreviousSection(sections, WasmSection::Code::Signatures, - true); int length; uint32_t functions_count = consume_u32v(&length, "functions count"); module->functions.reserve(SafeReserve(functions_count)); @@ -243,9 +236,6 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::Names: { - // Names correspond to functions. - CheckForPreviousSection(sections, - WasmSection::Code::FunctionSignatures, true); int length; const byte* pos = pc_; uint32_t functions_count = consume_u32v(&length, "functions count"); @@ -341,9 +331,6 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::ImportTable: { - // Declares an import table. - CheckForPreviousSection(sections, WasmSection::Code::Signatures, - true); int length; uint32_t import_table_count = consume_u32v(&length, "import table count"); @@ -392,7 +379,25 @@ class ModuleDecoder : public Decoder { break; } case WasmSection::Code::Max: - UNREACHABLE(); // Already skipped unknown sections. + // Skip unknown sections. + TRACE("Unknown section: '"); + for (uint32_t i = 0; i != string_length; ++i) { + TRACE("%c", *(section_name_start + i)); + } + TRACE("'\n"); + consume_bytes(section_length - string_length - string_leb_length); + break; + } + + if (pc_ != expected_section_end) { + const char* diff = pc_ < expected_section_end ? "shorter" : "longer"; + size_t expected_length = static_cast(section_length); + size_t actual_length = static_cast(pc_ - section_start); + error(pc_, pc_, + "section \"%s\" %s (%zu bytes) than specified (%zu bytes)", + WasmSection::getName(section), diff, actual_length, + expected_length); + break; } } @@ -417,17 +422,18 @@ class ModuleDecoder : public Decoder { } } - void CheckForPreviousSection(bool* sections, WasmSection::Code section, - bool present) { - if (section >= WasmSection::Code::Max) return; - if (sections[(size_t)section] == present) return; - if (present) { - error(pc_ - 1, nullptr, "required %s section missing", - WasmSection::getName(section)); - } else { - error(pc_ - 1, nullptr, "%s section already present", + int CheckSectionOrder(int current_order, WasmSection::Code section) { + int next_order = WasmSection::getOrder(section); + if (next_order == 0) return current_order; + if (next_order == current_order) { + error(pc_, pc_, "section \"%s\" already defined", WasmSection::getName(section)); } + if (next_order < current_order) { + error(pc_, pc_, "section \"%s\" out of order", + WasmSection::getName(section)); + } + return next_order; } // Decodes a single anonymous function starting at {start_}. @@ -643,30 +649,6 @@ class ModuleDecoder : public Decoder { return func_index; } - // Reads a section name. - WasmSection::Code consume_section_name(int* string_leb_length, - uint32_t* string_length) { - *string_length = consume_u32v(string_leb_length, "name length"); - const byte* start = pc_; - consume_bytes(*string_length); - if (failed()) { - TRACE("Section name of length %u couldn't be read\n", *string_length); - return WasmSection::Code::Max; - } - // TODO(jfb) Linear search, it may be better to do a common-prefix search. - for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end(); - i = WasmSection::next(i)) { - if (WasmSection::getNameLength(i) == *string_length && - 0 == memcmp(WasmSection::getName(i), start, *string_length)) { - return i; - } - } - TRACE("Unknown section: '"); - for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i)); - TRACE("'\n"); - return WasmSection::Code::Max; - } - // Reads a single 8-bit integer, interpreting it as a local type. LocalType consume_local_type() { byte val = consume_u8("local type"); diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc index 68ef6ba97d..e15b8d1f55 100644 --- a/src/wasm/wasm-module.cc +++ b/src/wasm/wasm-module.cc @@ -20,19 +20,28 @@ namespace internal { namespace wasm { static const char* wasmSections[] = { -#define F(enumerator, string) string, +#define F(enumerator, order, string) string, FOR_EACH_WASM_SECTION_TYPE(F) #undef F + "" // entry for "Max" }; static uint8_t wasmSectionsLengths[]{ -#define F(enumerator, string) sizeof(string) - 1, +#define F(enumerator, order, string) sizeof(string) - 1, FOR_EACH_WASM_SECTION_TYPE(F) #undef F + 9 // entry for "Max" +}; + +static uint8_t wasmSectionsOrders[]{ +#define F(enumerator, order, string) order, + FOR_EACH_WASM_SECTION_TYPE(F) +#undef F + 0 // entry for "Max" }; static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) == - (size_t)WasmSection::Code::Max, + (size_t)WasmSection::Code::Max + 1, "expected enum WasmSection::Code to be monotonic from 0"); WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; } @@ -49,6 +58,20 @@ size_t WasmSection::getNameLength(WasmSection::Code code) { return wasmSectionsLengths[(size_t)code]; } +int WasmSection::getOrder(WasmSection::Code code) { + return wasmSectionsOrders[(size_t)code]; +} + +WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) { + // TODO(jfb) Linear search, it may be better to do a common-prefix search. + for (Code i = begin(); i != end(); i = next(i)) { + if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) { + return i; + } + } + return Code::Max; +} + std::ostream& operator<<(std::ostream& os, const WasmModule& module) { os << "WASM module with "; os << (module.min_mem_pages * module.kPageSize) << " min mem"; diff --git a/src/wasm/wasm-module.h b/src/wasm/wasm-module.h index 4e5aa78486..78b780ace0 100644 --- a/src/wasm/wasm-module.h +++ b/src/wasm/wasm-module.h @@ -28,21 +28,21 @@ const uint32_t kWasmVersion = 0x0a; // WebAssembly sections are named as strings in the binary format, but // internally V8 uses an enum to handle them. // -// Entries have the form F(enumerator, string). -#define FOR_EACH_WASM_SECTION_TYPE(F) \ - F(Memory, "memory") \ - F(Signatures, "signatures") \ - F(Functions, "functions") \ - F(Globals, "globals") \ - F(DataSegments, "data_segments") \ - F(FunctionTable, "function_table") \ - F(End, "end") \ - F(StartFunction, "start_function") \ - F(ImportTable, "import_table") \ - F(ExportTable, "export_table") \ - F(FunctionSignatures, "function_signatures") \ - F(FunctionBodies, "function_bodies") \ - F(Names, "names") +// Entries have the form F(enumerator, order, string). +#define FOR_EACH_WASM_SECTION_TYPE(F) \ + F(Signatures, 1, "signatures") \ + F(ImportTable, 2, "import_table") \ + F(FunctionSignatures, 3, "function_signatures") \ + F(FunctionTable, 4, "function_table") \ + F(Memory, 5, "memory") \ + F(ExportTable, 6, "export_table") \ + F(StartFunction, 7, "start_function") \ + F(FunctionBodies, 8, "function_bodies") \ + F(DataSegments, 9, "data_segments") \ + F(Names, 10, "names") \ + F(Globals, 0, "globals") \ + F(Functions, 0, "functions") \ + F(End, 0, "end") // Contants for the above section types: {LEB128 length, characters...}. #define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y' @@ -85,7 +85,7 @@ const uint32_t kWasmVersion = 0x0a; struct WasmSection { enum class Code : uint32_t { -#define F(enumerator, string) enumerator, +#define F(enumerator, order, string) enumerator, FOR_EACH_WASM_SECTION_TYPE(F) #undef F Max @@ -94,7 +94,9 @@ struct WasmSection { static WasmSection::Code end(); static WasmSection::Code next(WasmSection::Code code); static const char* getName(Code code); + static int getOrder(Code code); static size_t getNameLength(Code code); + static WasmSection::Code lookup(const byte* string, uint32_t length); }; enum WasmFunctionDeclBit { diff --git a/test/mjsunit/wasm/wasm-module-builder.js b/test/mjsunit/wasm/wasm-module-builder.js index e1d996338c..1c13890920 100644 --- a/test/mjsunit/wasm/wasm-module-builder.js +++ b/test/mjsunit/wasm/wasm-module-builder.js @@ -149,16 +149,6 @@ WasmModuleBuilder.prototype.toArray = function(debug) { var wasm = this; - // Add memory section - if (wasm.memory != undefined) { - if (debug) print("emitting memory @ " + bytes.length); - emit_section(bytes, kDeclMemory, function(bytes) { - emit_varint(bytes, wasm.memory.min); - emit_varint(bytes, wasm.memory.max); - emit_u8(bytes, wasm.memory.exp ? 1 : 0); - }); - } - // Add signatures section if (wasm.signatures.length > 0) { if (debug) print("emitting signatures @ " + bytes.length); @@ -187,7 +177,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) { }); } - // Add functions section + // Add functions declarations var names = false; var exports = 0; if (wasm.functions.length > 0) { @@ -206,6 +196,54 @@ WasmModuleBuilder.prototype.toArray = function(debug) { } }); + } + + // Add function table. + if (wasm.function_table.length > 0) { + if (debug) print("emitting function table @ " + bytes.length); + emit_section(bytes, kDeclFunctionTable, function(bytes) { + emit_varint(bytes, wasm.function_table.length); + for (index of wasm.function_table) { + emit_varint(bytes, index); + } + }); + } + + // Add memory section + if (wasm.memory != undefined) { + if (debug) print("emitting memory @ " + bytes.length); + emit_section(bytes, kDeclMemory, function(bytes) { + emit_varint(bytes, wasm.memory.min); + emit_varint(bytes, wasm.memory.max); + emit_u8(bytes, wasm.memory.exp ? 1 : 0); + }); + } + + + // Add export table. + if (exports > 0) { + if (debug) print("emitting exports @ " + bytes.length); + emit_section(bytes, kDeclExportTable, function(bytes) { + emit_varint(bytes, exports); + for (func of wasm.functions) { + for (exp of func.exports) { + emit_varint(bytes, func.index); + emit_string(bytes, exp); + } + } + }); + } + + // Add start function section. + if (wasm.start_index != undefined) { + if (debug) print("emitting start function @ " + bytes.length); + emit_section(bytes, kDeclStartFunction, function(bytes) { + emit_varint(bytes, wasm.start_index); + }); + } + + // Add function bodies. + if (wasm.functions.length > 0) { // emit function bodies if (debug) print("emitting function bodies @ " + bytes.length); emit_section(bytes, kDeclFunctionBodies, function(bytes) { @@ -244,50 +282,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) { }); } - // emit function names - if (has_names) { - if (debug) print("emitting names @ " + bytes.length); - emit_section(bytes, kDeclNames, function(bytes) { - emit_varint(bytes, wasm.functions.length); - for (func of wasm.functions) { - var name = func.name == undefined ? "" : func.name; - emit_string(bytes, name); - emit_u8(bytes, 0); // local names count == 0 - } - }); - } - - // Add start function section. - if (wasm.start_index != undefined) { - if (debug) print("emitting start function @ " + bytes.length); - emit_section(bytes, kDeclStartFunction, function(bytes) { - emit_varint(bytes, wasm.start_index); - }); - } - - if (wasm.function_table.length > 0) { - if (debug) print("emitting function table @ " + bytes.length); - emit_section(bytes, kDeclFunctionTable, function(bytes) { - emit_varint(bytes, wasm.function_table.length); - for (index of wasm.function_table) { - emit_varint(bytes, index); - } - }); - } - - if (exports > 0) { - if (debug) print("emitting exports @ " + bytes.length); - emit_section(bytes, kDeclExportTable, function(bytes) { - emit_varint(bytes, exports); - for (func of wasm.functions) { - for (exp of func.exports) { - emit_varint(bytes, func.index); - emit_string(bytes, exp); - } - } - }); - } - + // Add data segments. if (wasm.data_segments.length > 0) { if (debug) print("emitting data segments @ " + bytes.length); emit_section(bytes, kDeclDataSegments, function(bytes) { @@ -300,12 +295,25 @@ WasmModuleBuilder.prototype.toArray = function(debug) { }); } - // Emit any explicitly added sections + // Add any explicitly added sections for (exp of wasm.explicit) { if (debug) print("emitting explicit @ " + bytes.length); emit_bytes(bytes, exp); } + // Add function names. + if (has_names) { + if (debug) print("emitting names @ " + bytes.length); + emit_section(bytes, kDeclNames, function(bytes) { + emit_varint(bytes, wasm.functions.length); + for (func of wasm.functions) { + var name = func.name == undefined ? "" : func.name; + emit_string(bytes, name); + emit_u8(bytes, 0); // local names count == 0 + } + }); + } + // End the module. if (debug) print("emitting end @ " + bytes.length); emit_section(bytes, kDeclEnd, function(bytes) {}); diff --git a/test/unittests/wasm/module-decoder-unittest.cc b/test/unittests/wasm/module-decoder-unittest.cc index cfff90b593..88a4ee5e44 100644 --- a/test/unittests/wasm/module-decoder-unittest.cc +++ b/test/unittests/wasm/module-decoder-unittest.cc @@ -23,6 +23,7 @@ namespace wasm { #define INT_INT_SIG 1, kLocalI32, kLocalI32 #define INT_INT_SIG_SIZE ((size_t)3) +// TODO(titzer): tricky size logic! Remove -1. #define SECTION(NAME, EXTRA_SIZE) \ U32V_1(WASM_SECTION_##NAME##_SIZE + (EXTRA_SIZE)), WASM_SECTION_##NAME @@ -49,6 +50,15 @@ namespace wasm { } \ } while (false) +#define EXPECT_OK(result) \ + do { \ + EXPECT_TRUE(result.ok()); \ + if (!result.ok()) { \ + if (result.val) delete result.val; \ + return; \ + } \ + } while (false) + static size_t SizeOfVarInt(size_t value) { size_t size = 0; do { @@ -115,7 +125,7 @@ TEST_F(WasmModuleVerifyTest, DecodeEmpty) { TEST_F(WasmModuleVerifyTest, OneGlobal) { static const byte data[] = { - SECTION(GLOBALS, 7), // -- + SECTION(GLOBALS, 5), // -- 1, NAME_LENGTH(1), 'g', // name @@ -126,7 +136,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) { { // Should decode to exactly one global. ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->globals.size()); EXPECT_EQ(0, result.val->functions.size()); EXPECT_EQ(0, result.val->data_segments.size()); @@ -151,7 +161,7 @@ TEST_F(WasmModuleVerifyTest, ZeroGlobals) { 0, // declare 0 globals }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); if (result.val) delete result.val; } @@ -192,7 +202,7 @@ TEST_F(WasmModuleVerifyTest, NGlobals) { } ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size()); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); if (result.val) delete result.val; } } @@ -224,7 +234,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { TEST_F(WasmModuleVerifyTest, TwoGlobals) { static const byte data[] = { - SECTION(GLOBALS, 13), + SECTION(GLOBALS, 7), 2, NO_NAME, // #0: name length kMemF32, // memory type @@ -237,7 +247,7 @@ TEST_F(WasmModuleVerifyTest, TwoGlobals) { { // Should decode to exactly two globals. ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(2, result.val->globals.size()); EXPECT_EQ(0, result.val->functions.size()); EXPECT_EQ(0, result.val->data_segments.size()); @@ -293,7 +303,7 @@ TEST_F(WasmModuleVerifyTest, MultipleSignatures) { }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(3, result.val->signatures.size()); if (result.val->signatures.size() == 3) { EXPECT_EQ(0, result.val->signatures[0]->return_count()); @@ -341,7 +351,7 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { // sig#0 ------------------------------------------------------- VOID_VOID_SIG, // func#0 ------------------------------------------------------ - SECTION(FUNCTIONS, 19), 1, + SECTION(FUNCTIONS, 18), 1, kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName, SIG_INDEX(0), // signature index NAME_LENGTH(2), 'h', 'i', // name @@ -356,7 +366,7 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { { // Should decode to exactly one function. ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(0, result.val->globals.size()); EXPECT_EQ(1, result.val->signatures.size()); EXPECT_EQ(1, result.val->functions.size()); @@ -387,16 +397,19 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { TEST_F(WasmModuleVerifyTest, OneFunctionImported) { static const byte data[] = { - SECTION(SIGNATURES, VOID_VOID_SIG_SIZE), 1, + // signatures + SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1, // sig#0 ------------------------------------------------------- - VOID_VOID_SIG, SECTION(FUNCTIONS, 6), 1, + VOID_VOID_SIG, + // functions + SECTION(FUNCTIONS, 4), 1, // func#0 ------------------------------------------------------ kDeclFunctionImport, // no name, no locals, imported SIG_INDEX(0), }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->functions.size()); WasmFunction* function = &result.val->functions.back(); @@ -432,7 +445,7 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) { }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->functions.size()); WasmFunction* function = &result.val->functions.back(); @@ -472,7 +485,7 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->functions.size()); WasmFunction* function = &result.val->functions.back(); @@ -493,33 +506,35 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { - static const byte kCodeStartOffset = 75; + static const byte kCodeStartOffset = 64; static const byte kCodeEndOffset = kCodeStartOffset + 3; - static const byte kDataSegmentSourceOffset = kCodeEndOffset + 20; + static const byte kDataSegmentSourceOffset = kCodeEndOffset + 31; static const byte data[] = { - SECTION(MEMORY, 3), 28, 28, 1, // global#0 -------------------------------------------------- - SECTION(GLOBALS, 7), 1, + SECTION(GLOBALS, 4), 1, 0, // name length kMemU8, // memory type 0, // exported // sig#0 ----------------------------------------------------- SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void // func#0 ---------------------------------------------------- - SECTION(FUNCTIONS, 20), 1, kDeclFunctionLocals | kDeclFunctionName, 0, - 0, // signature index - 2, 'h', 'i', // name - 1, 2, // local int32 count - 3, 4, // local int64 count - 5, 6, // local float32 count - 7, 8, // local float64 count - 3, 0, // body size - kExprNop, // func#0 body - kExprNop, // func#0 body - kExprNop, // func#0 body + SECTION(FUNCTIONS, 20), 1, + kDeclFunctionLocals | kDeclFunctionName, // -- + SIG_INDEX(0), // signature index + 2, 'h', 'i', // name + 1, 2, // local int32 count + 3, 4, // local int64 count + 5, 6, // local float32 count + 7, 8, // local float64 count + 3, 0, // body size + kExprNop, // func#0 body + kExprNop, // func#0 body + kExprNop, // func#0 body + // memory section -------------------------------------------- + SECTION(MEMORY, 3), 28, 28, 1, // segment#0 ------------------------------------------------- - SECTION(DATA_SEGMENTS, 14), 1, + SECTION(DATA_SEGMENTS, 10), 1, U32V_3(0x8b3ae), // dest addr U32V_1(5), // source size 0, 1, 2, 3, 4, // data bytes @@ -529,7 +544,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { { ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->globals.size()); EXPECT_EQ(1, result.val->functions.size()); EXPECT_EQ(1, result.val->data_segments.size()); @@ -543,7 +558,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { WasmFunction* function = &result.val->functions.back(); - EXPECT_EQ(63, function->name_offset); + EXPECT_EQ(52, function->name_offset); EXPECT_EQ(2, function->name_length); EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); @@ -582,7 +597,7 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { { EXPECT_VERIFIES(data); ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(0, result.val->globals.size()); EXPECT_EQ(0, result.val->functions.size()); EXPECT_EQ(1, result.val->data_segments.size()); @@ -610,7 +625,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { 28, 28, 1, - SECTION(DATA_SEGMENTS, 31), + SECTION(DATA_SEGMENTS, 23), 2, // segment count U32V_3(0x7ffee), // #0: dest addr U32V_1(4), // source size @@ -634,7 +649,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { { ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(0, result.val->globals.size()); EXPECT_EQ(0, result.val->functions.size()); EXPECT_EQ(2, result.val->data_segments.size()); @@ -670,7 +685,7 @@ TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidDest) { mem_pages, mem_pages, 1, - SECTION(DATA_SEGMENTS, 14), + SECTION(DATA_SEGMENTS, 8), 1, U32V_3(dest_addr), U32V_1(source_size), @@ -701,7 +716,7 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) { SECTION(FUNCTION_TABLE, 2), 1, U32V_1(0)}; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); if (result.ok()) { EXPECT_EQ(1, result.val->signatures.size()); EXPECT_EQ(1, result.val->functions.size()); @@ -735,7 +750,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) { }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); if (result.ok()) { EXPECT_EQ(2, result.val->signatures.size()); EXPECT_EQ(4, result.val->functions.size()); @@ -916,7 +931,7 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { FunctionResult result = DecodeWasmFunction(isolate(), zone(), nullptr, data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); if (result.val && result.ok()) { WasmFunction* function = result.val; @@ -1031,14 +1046,14 @@ TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) { 1, '\0', // Section name: LEB128 1, string '\0' 0, // one byte section - SECTION(GLOBALS, 7), + SECTION(GLOBALS, 4), 1, 0, // name length kMemI32, // memory type 0, // exported }; ModuleResult result = DecodeModule(data, data + arraysize(data)); - EXPECT_TRUE(result.ok()); + EXPECT_OK(result); EXPECT_EQ(1, result.val->globals.size()); EXPECT_EQ(0, result.val->functions.size()); @@ -1060,8 +1075,18 @@ TEST_F(WasmModuleVerifyTest, ImportTable_empty) { EXPECT_VERIFIES(data); } -TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) { +TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) { static const byte data[] = {SECTION(IMPORT_TABLE, 1), 0}; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_nosigs2) { + static const byte data[] = { + SECTION(IMPORT_TABLE, 6), 1, // sig table + IMPORT_SIG_INDEX(0), // sig index + NAME_LENGTH(1), 'm', // module name + NAME_LENGTH(1), 'f', // function name + }; EXPECT_FAILURE(data); } @@ -1162,7 +1187,7 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne) { SECTION(FUNCTIONS, 1 + EMPTY_FUNCTION_SIZE), 1, // functions EMPTY_FUNCTION(0), // -- - SECTION(EXPORT_TABLE, 7), + SECTION(EXPORT_TABLE, 3), 1, // exports FUNC_INDEX(0), // -- NO_NAME // -- @@ -1269,7 +1294,7 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) { } #define SIGNATURES_SECTION(count, ...) \ - SECTION(SIGNATURES, 1 + 3 * (count)), U32V_1(count), __VA_ARGS__ + SECTION(SIGNATURES, 1 + 2 * (count)), U32V_1(count), __VA_ARGS__ #define FUNCTION_SIGNATURES_SECTION(count, ...) \ SECTION(FUNCTION_SIGNATURES, 1 + (count)), U32V_1(count), __VA_ARGS__ @@ -1282,53 +1307,67 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) { #define EMPTY_NAMES_SECTION SECTION(NAMES, 1), 0 TEST_F(WasmModuleVerifyTest, FunctionSignatures_empty) { - static const byte data[] = {SECTION(SIGNATURES, 1), 0, - SECTION(FUNCTION_SIGNATURES, 1), 0}; + static const byte data[] = { + SECTION(SIGNATURES, 1), 0, // -- + SECTION(FUNCTION_SIGNATURES, 1), 0 // -- + }; // -- EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionSignatures_one) { - static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG), - FUNCTION_SIGNATURES_SECTION(1, 0)}; + static const byte data[] = { + SIGNATURES_SECTION(1, VOID_VOID_SIG), // -- + FUNCTION_SIGNATURES_SECTION(1, 0) // -- + }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_empty) { - static const byte data[] = {EMPTY_SIGNATURES_SECTION, - EMPTY_FUNCTION_SIGNATURES_SECTION, - EMPTY_FUNCTION_BODIES_SECTION}; + static const byte data[] = { + EMPTY_SIGNATURES_SECTION, // -- + EMPTY_FUNCTION_SIGNATURES_SECTION, // -- + EMPTY_FUNCTION_BODIES_SECTION // -- + }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_one_empty) { static const byte data[] = { - SIGNATURES_SECTION(1, VOID_VOID_SIG), FUNCTION_SIGNATURES_SECTION(1, 0), - SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, EMPTY_BODY}; + SIGNATURES_SECTION(1, VOID_VOID_SIG), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, EMPTY_BODY // -- + }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_one_nop) { static const byte data[] = { - SIGNATURES_SECTION(1, VOID_VOID_SIG), FUNCTION_SIGNATURES_SECTION(1, 0), - SECTION(FUNCTION_BODIES, 1 + NOP_BODY_SIZE), 1, NOP_BODY}; + SIGNATURES_SECTION(1, VOID_VOID_SIG), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + SECTION(FUNCTION_BODIES, 1 + NOP_BODY_SIZE), 1, NOP_BODY // -- + }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch1) { - static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG), - FUNCTION_SIGNATURES_SECTION(2, 0, 0), - SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, - EMPTY_BODY}; + static const byte data[] = { + SIGNATURES_SECTION(1, VOID_VOID_SIG), // -- + FUNCTION_SIGNATURES_SECTION(2, 0, 0), // -- + SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, // -- + EMPTY_BODY // -- + }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch2) { - static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG), - FUNCTION_SIGNATURES_SECTION(1, 0), - SECTION(FUNCTION_BODIES, 1 + 2 * NOP_BODY_SIZE), - 2, - NOP_BODY, - NOP_BODY}; + static const byte data[] = { + SIGNATURES_SECTION(1, VOID_VOID_SIG), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + SECTION(FUNCTION_BODIES, 1 + 2 * NOP_BODY_SIZE), // -- + 2, // -- + NOP_BODY, // -- + NOP_BODY // -- + }; EXPECT_FAILURE(data); }