Commit d7a5e5ba authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Fix section order checking in {StreamingDecoder}.

This removes an outdated section order check from {CreateNewBuffer} and
relies solely on the checks done in {ProcessSection}. Those checks are
more comprehensive and will remain coherent with synchronous decoding.

R=ahaas@chromium.org
TEST=mjsunit/regress/wasm/regress-8846
BUG=v8:8846

Change-Id: Id0cdc3bf3ad78f7970c9fceff66a17ab20f4666b
Reviewed-on: https://chromium-review.googlesource.com/c/1477211Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59702}
parent efabac6e
......@@ -1174,8 +1174,6 @@ class ModuleDecoderImpl : public Decoder {
}
}
// Decodes a single data segment entry inside a module starting at {pc_}.
// Calculate individual global offsets and total size of globals table.
void CalculateGlobalOffsets(WasmModule* module) {
uint32_t untagged_offset = 0;
......
......@@ -380,11 +380,13 @@ StreamingDecoder::DecodeSectionLength::NextWithValue(
SectionBuffer* buf =
streaming->CreateNewBuffer(module_offset_, section_id_, value_,
buffer().SubVector(0, bytes_consumed_));
if (!buf) return nullptr;
DCHECK_NOT_NULL(buf);
if (value_ == 0) {
if (section_id_ == SectionCode::kCodeSectionCode) {
return streaming->Error("code section cannot have size 0");
}
// Process section without payload as well, to enforce section order and
// other feature checks specific to each individual section.
streaming->ProcessSection(buf);
if (!streaming->ok()) return nullptr;
// There is no payload, we go to the next section immediately.
......@@ -483,14 +485,8 @@ StreamingDecoder::StreamingDecoder(
StreamingDecoder::SectionBuffer* StreamingDecoder::CreateNewBuffer(
uint32_t module_offset, uint8_t section_id, size_t length,
Vector<const uint8_t> length_bytes) {
// Check the order of sections. Unknown sections can appear at any position.
if (section_id != kUnknownSectionCode) {
if (section_id < next_section_id_) {
Error("section out of order");
return nullptr;
}
next_section_id_ = section_id + 1;
}
// Section buffers are allocated in the same order they appear in the module,
// they will be processed and later on concatenated in that same order.
section_buffers_.emplace_back(std::make_shared<SectionBuffer>(
module_offset, section_id, length, length_bytes));
return section_buffers_.back().get();
......
......@@ -263,7 +263,6 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
std::vector<std::shared_ptr<SectionBuffer>> section_buffers_;
uint32_t module_offset_ = 0;
size_t total_size_ = 0;
uint8_t next_section_id_ = kFirstSectionInModule;
// Caching support.
ModuleCompiledCallback module_compiled_callback_ = nullptr;
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-eh --wasm-test-streaming
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestAsyncCompileExceptionSection() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let except = builder.addException(kSig_v_v);
builder.addFunction("thrw", kSig_v_v)
.addBody([
kExprThrow, except,
]).exportFunc();
function step1(buffer) {
assertPromiseResult(WebAssembly.compile(buffer), module => step2(module));
}
function step2(module) {
assertPromiseResult(WebAssembly.instantiate(module), inst => step3(inst));
}
function step3(instance) {
assertThrows(() => instance.exports.thrw(), WebAssembly.RuntimeError);
}
step1(builder.toBuffer());
})();
......@@ -35,7 +35,6 @@ class MockStreamingProcessor : public StreamingProcessor {
bool ProcessModuleHeader(Vector<const uint8_t> bytes,
uint32_t offset) override {
// TODO(ahaas): Share code with the module-decoder.
Decoder decoder(bytes.begin(), bytes.end());
uint32_t magic_word = decoder.consume_u32("wasm magic");
if (decoder.failed() || magic_word != kWasmMagic) {
......@@ -49,15 +48,30 @@ class MockStreamingProcessor : public StreamingProcessor {
}
return true;
}
// Process all sections but the code section.
bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
uint32_t offset) override {
// Mock a simple processor that rejects non-consecutive section codes.
if (section_code != kUnknownSectionCode) {
if (section_code < next_section_) {
result_->error = WasmError(0, "section out of order");
return false;
}
next_section_ = section_code + 1;
}
++result_->num_sections;
return true;
}
bool ProcessCodeSectionHeader(size_t num_functions, uint32_t offset,
std::shared_ptr<WireBytesStorage>) override {
// Mock a simple processor that rejects non-consecutive section codes.
if (kCodeSectionCode < next_section_) {
result_->error = WasmError(0, "section out of order");
return false;
}
next_section_ = kCodeSectionCode + 1;
return true;
}
......@@ -90,6 +104,7 @@ class MockStreamingProcessor : public StreamingProcessor {
private:
MockStreamingResult* const result_;
uint8_t next_section_ = kFirstSectionInModule;
};
class WasmStreamingDecoderTest : public ::testing::Test {
......@@ -122,8 +137,6 @@ class WasmStreamingDecoderTest : public ::testing::Test {
EXPECT_EQ(message, result.error.message());
}
}
MockStreamingResult result;
};
TEST_F(WasmStreamingDecoderTest, EmptyStream) {
......
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