Index: src/wasm/module-decoder.cc |
diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc |
index f09e4ea77b2ebe1d6384c9b23ab9ee4b64338553..25ce7b6cd72d4cdd1518c43e2cacd704544535a7 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; |
} |
- |
- 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; |
+ const byte* section_start = pc_; |
+ const byte* expected_section_end = pc_ + section_length; |
+ |
+ // 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); |
+ } |
+ |
+ WasmSection::Code section = |
+ WasmSection::lookup(section_name_start, string_length); |
- // Each section should appear at most once. |
- CheckForPreviousSection(sections, section, false); |
- sections[(size_t)section] = true; |
+ 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<size_t>(section_length); |
+ size_t actual_length = static_cast<size_t>(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", |
+ 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)); |
- } else { |
- error(pc_ - 1, nullptr, "%s section already present", |
+ } |
+ 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"); |