Commit cc4bd491 authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

[wasm] fix name section errors

This CL ignores multiple name sections in wasm modules instead throwing an error.
This is in line with the spec with regards to custom sections.

BUG=v8:8186
R=clemensh@chromium.org,adamk@chromium.org

Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I8c6610afe389d8f8d03f9fca164bd46cb5fb030d
Reviewed-on: https://chromium-review.googlesource.com/1232676
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56152}
parent 0cec56a4
...@@ -342,7 +342,8 @@ class ModuleDecoderImpl : public Decoder { ...@@ -342,7 +342,8 @@ class ModuleDecoderImpl : public Decoder {
static_cast<const void*>(bytes.end())); static_cast<const void*>(bytes.end()));
// Check if the section is out-of-order. // Check if the section is out-of-order.
if (section_code < next_ordered_section_) { if (section_code < next_ordered_section_ &&
section_code < kFirstUnorderedSection) {
errorf(pc(), "unexpected section: %s", SectionName(section_code)); errorf(pc(), "unexpected section: %s", SectionName(section_code));
return; return;
} }
...@@ -354,7 +355,7 @@ class ModuleDecoderImpl : public Decoder { ...@@ -354,7 +355,7 @@ class ModuleDecoderImpl : public Decoder {
// Note: kExceptionSectionCode > kExportSectionCode, but must appear // Note: kExceptionSectionCode > kExportSectionCode, but must appear
// before the export (and code) section, as well as after the import // before the export (and code) section, as well as after the import
// section. Hence, treat it as a special case. // section. Hence, treat it as a special case.
if (++number_of_exception_sections > 1) { if (seen_unordered_sections_ & (1 << kExceptionSectionCode)) {
errorf(pc(), "Multiple exception sections not allowed"); errorf(pc(), "Multiple exception sections not allowed");
return; return;
} else if (next_ordered_section_ > kExportSectionCode) { } else if (next_ordered_section_ > kExportSectionCode) {
...@@ -363,11 +364,16 @@ class ModuleDecoderImpl : public Decoder { ...@@ -363,11 +364,16 @@ class ModuleDecoderImpl : public Decoder {
} else if (next_ordered_section_ < kImportSectionCode) { } else if (next_ordered_section_ < kImportSectionCode) {
next_ordered_section_ = kImportSectionCode + 1; next_ordered_section_ = kImportSectionCode + 1;
} }
seen_unordered_sections_ |= 1 << kExceptionSectionCode;
break; break;
case kSourceMappingURLSectionCode: case kSourceMappingURLSectionCode:
// sourceMappingURL is a custom section and currently can occur anywhere // sourceMappingURL is a custom section and currently can occur anywhere
// in the module. In case of multiple sourceMappingURL sections, all // in the module. In case of multiple sourceMappingURL sections, all
// except the first occurrence are ignored. // except the first occurrence are ignored.
case kNameSectionCode:
// TODO(titzer): report out of place name section as a warning.
// Be lenient with placement of name section. All except first
// occurrence are ignored.
break; break;
default: default:
next_ordered_section_ = section_code + 1; next_ordered_section_ = section_code + 1;
...@@ -838,24 +844,28 @@ class ModuleDecoderImpl : public Decoder { ...@@ -838,24 +844,28 @@ class ModuleDecoderImpl : public Decoder {
void DecodeNameSection() { void DecodeNameSection() {
// TODO(titzer): find a way to report name errors as warnings. // TODO(titzer): find a way to report name errors as warnings.
// Use an inner decoder so that errors don't fail the outer decoder. // ignore all but the first occurrence of name section.
Decoder inner(start_, pc_, end_, buffer_offset_); if (!(seen_unordered_sections_ & (1 << kNameSectionCode))) {
// Decode all name subsections. seen_unordered_sections_ |= 1 << kNameSectionCode;
// Be lenient with their order. // Use an inner decoder so that errors don't fail the outer decoder.
while (inner.ok() && inner.more()) { Decoder inner(start_, pc_, end_, buffer_offset_);
uint8_t name_type = inner.consume_u8("name type"); // Decode all name subsections.
if (name_type & 0x80) inner.error("name type if not varuint7"); // Be lenient with their order.
while (inner.ok() && inner.more()) {
uint32_t name_payload_len = inner.consume_u32v("name payload length"); uint8_t name_type = inner.consume_u8("name type");
if (!inner.checkAvailable(name_payload_len)) break; if (name_type & 0x80) inner.error("name type if not varuint7");
// Decode module name, ignore the rest. uint32_t name_payload_len = inner.consume_u32v("name payload length");
// Function and local names will be decoded when needed. if (!inner.checkAvailable(name_payload_len)) break;
if (name_type == NameSectionKindCode::kModule) {
WireBytesRef name = consume_string(inner, false, "module name"); // Decode module name, ignore the rest.
if (inner.ok() && validate_utf8(&inner, name)) module_->name = name; // Function and local names will be decoded when needed.
} else { if (name_type == NameSectionKindCode::kModule) {
inner.consume_bytes(name_payload_len, "name subsection payload"); WireBytesRef name = consume_string(inner, false, "module name");
if (inner.ok() && validate_utf8(&inner, name)) module_->name = name;
} else {
inner.consume_bytes(name_payload_len, "name subsection payload");
}
} }
} }
// Skip the whole names section in the outer decoder. // Skip the whole names section in the outer decoder.
...@@ -865,12 +875,13 @@ class ModuleDecoderImpl : public Decoder { ...@@ -865,12 +875,13 @@ class ModuleDecoderImpl : public Decoder {
void DecodeSourceMappingURLSection() { void DecodeSourceMappingURLSection() {
Decoder inner(start_, pc_, end_, buffer_offset_); Decoder inner(start_, pc_, end_, buffer_offset_);
WireBytesRef url = wasm::consume_string(inner, true, "module name"); WireBytesRef url = wasm::consume_string(inner, true, "module name");
if (inner.ok() && !source_mapping_url_section_added) { if (inner.ok() &&
!(seen_unordered_sections_ & (1 << kSourceMappingURLSectionCode))) {
const byte* url_start = const byte* url_start =
inner.start() + inner.GetBufferRelativeOffset(url.offset()); inner.start() + inner.GetBufferRelativeOffset(url.offset());
module_->source_map_url.assign(reinterpret_cast<const char*>(url_start), module_->source_map_url.assign(reinterpret_cast<const char*>(url_start),
url.length()); url.length());
source_mapping_url_section_added = true; seen_unordered_sections_ |= 1 << kSourceMappingURLSectionCode;
} }
consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
} }
...@@ -984,14 +995,17 @@ class ModuleDecoderImpl : public Decoder { ...@@ -984,14 +995,17 @@ class ModuleDecoderImpl : public Decoder {
Counters* counters_ = nullptr; Counters* counters_ = nullptr;
// The type section is the first section in a module. // The type section is the first section in a module.
uint8_t next_ordered_section_ = kFirstSectionInModule; uint8_t next_ordered_section_ = kFirstSectionInModule;
bool source_mapping_url_section_added = false;
uint32_t number_of_exception_sections = 0;
// We store next_ordered_section_ as uint8_t instead of SectionCode so that we // We store next_ordered_section_ as uint8_t instead of SectionCode so that we
// can increment it. This static_assert should make sure that SectionCode does // can increment it. This static_assert should make sure that SectionCode does
// not get bigger than uint8_t accidentially. // not get bigger than uint8_t accidentially.
static_assert(sizeof(ModuleDecoderImpl::next_ordered_section_) == static_assert(sizeof(ModuleDecoderImpl::next_ordered_section_) ==
sizeof(SectionCode), sizeof(SectionCode),
"type mismatch"); "type mismatch");
uint32_t seen_unordered_sections_ = 0;
static_assert(kBitsPerByte *
sizeof(ModuleDecoderImpl::seen_unordered_sections_) >
kLastKnownModuleSection,
"not enough bits");
Result<bool> intermediate_result_; Result<bool> intermediate_result_;
ModuleOrigin origin_; ModuleOrigin origin_;
...@@ -1668,7 +1682,7 @@ std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start, ...@@ -1668,7 +1682,7 @@ std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
namespace { namespace {
bool FindSection(Decoder& decoder, SectionCode section_code) { bool FindNameSection(Decoder& decoder) {
static constexpr int kModuleHeaderSize = 8; static constexpr int kModuleHeaderSize = 8;
decoder.consume_bytes(kModuleHeaderSize, "module header"); decoder.consume_bytes(kModuleHeaderSize, "module header");
...@@ -1693,7 +1707,7 @@ void DecodeFunctionNames(const byte* module_start, const byte* module_end, ...@@ -1693,7 +1707,7 @@ void DecodeFunctionNames(const byte* module_start, const byte* module_end,
DCHECK(names->empty()); DCHECK(names->empty());
Decoder decoder(module_start, module_end); Decoder decoder(module_start, module_end);
if (!FindSection(decoder, kNameSectionCode)) return; if (!FindNameSection(decoder)) return;
while (decoder.ok() && decoder.more()) { while (decoder.ok() && decoder.more()) {
uint8_t name_type = decoder.consume_u8("name type"); uint8_t name_type = decoder.consume_u8("name type");
...@@ -1728,7 +1742,7 @@ void DecodeLocalNames(const byte* module_start, const byte* module_end, ...@@ -1728,7 +1742,7 @@ void DecodeLocalNames(const byte* module_start, const byte* module_end,
DCHECK(result->names.empty()); DCHECK(result->names.empty());
Decoder decoder(module_start, module_end); Decoder decoder(module_start, module_end);
if (!FindSection(decoder, kNameSectionCode)) return; if (!FindNameSection(decoder)) return;
while (decoder.ok() && decoder.more()) { while (decoder.ok() && decoder.more()) {
uint8_t name_type = decoder.consume_u8("name type"); uint8_t name_type = decoder.consume_u8("name type");
......
...@@ -71,6 +71,7 @@ enum SectionCode : int8_t { ...@@ -71,6 +71,7 @@ enum SectionCode : int8_t {
// Helper values // Helper values
kFirstSectionInModule = kTypeSectionCode, kFirstSectionInModule = kTypeSectionCode,
kLastKnownModuleSection = kSourceMappingURLSectionCode, kLastKnownModuleSection = kSourceMappingURLSectionCode,
kFirstUnorderedSection = kNameSectionCode,
}; };
// Binary encoding of name section kinds. // Binary encoding of name section kinds.
......
...@@ -2335,6 +2335,31 @@ TEST_F(WasmModuleVerifyTest, MultipleSourceMappingURLSections) { ...@@ -2335,6 +2335,31 @@ TEST_F(WasmModuleVerifyTest, MultipleSourceMappingURLSections) {
} }
#undef SRC_MAP #undef SRC_MAP
TEST_F(WasmModuleVerifyTest, MultipleNameSections) {
#define NAME_SECTION 4, 'n', 'a', 'm', 'e'
static const byte data[] = {SECTION(Unknown, 11),
NAME_SECTION,
0,
4,
3,
'a',
'b',
'c',
SECTION(Unknown, 12),
NAME_SECTION,
0,
5,
4,
'p',
'q',
'r',
's'};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_TRUE(result.ok());
EXPECT_EQ(3u, result.val->name.length());
#undef NAME_SECTION
}
#undef WASM_FEATURE_SCOPE #undef WASM_FEATURE_SCOPE
#undef WASM_FEATURE_SCOPE_VAL #undef WASM_FEATURE_SCOPE_VAL
#undef EXPECT_INIT_EXPR #undef EXPECT_INIT_EXPR
......
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