Chromium Code Reviews| Index: src/wasm/module-decoder.cc |
| diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc |
| index 0189b2af524febbb2397e79442cc0057332b1bfb..04083efe1c42d81ceee994921b0117b79d4ec918 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,59 @@ class ModuleDecoder : public Decoder { |
| TRACE("DecodeSection\n"); |
| pos = pc_; |
| - int length; |
| - uint32_t section_length = consume_u32v(&length, "section size"); |
| + // 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; |
| + } |
| - 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 the section name. |
| + int string_leb_length = 0; |
| + uint32_t string_length = |
| + consume_u32v(&string_leb_length, "section name length"); |
| + if (static_cast<uint32_t>(string_leb_length) + string_length > |
| + section_length) { |
|
JF
2016/04/19 15:48:47
This seems pretty impossible to cause to overflow,
titzer
2016/04/20 08:51:24
Done. (I've refactored this a bit so the check is
|
| + error(pc_, pc_, |
| + "section name string %u longer than total section bytes %u", |
| + string_length, section_length); |
| break; |
| } |
| + 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; |
| + } |
| + |
| + WasmSection::Code section = |
| + WasmSection::lookup(section_name_start, string_length); |
| + // 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), section_name_start, |
| + string_length)) { |
| + section = i; |
| + break; |
| + } |
| + } |
|
JF
2016/04/19 15:48:47
Duplicate.
titzer
2016/04/20 08:51:24
Done.
|
| + |
| 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); |
| + // 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); |
| continue; |
| } |
| - // 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 +187,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 +199,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 +225,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 +258,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 +353,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"); |
| @@ -417,17 +426,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 +653,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"); |