// Copyright 2017 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. #include "test/unittests/test-utils.h" #include "src/objects-inl.h" #include "src/wasm/module-decoder.h" #include "src/wasm/streaming-decoder.h" #include "src/objects/descriptor-array.h" #include "src/objects/dictionary.h" #include "test/common/wasm/wasm-macro-gen.h" namespace v8 { namespace internal { namespace wasm { class MockStreamingProcessor : public StreamingProcessor { public: bool ProcessModuleHeader(Vector 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) { ok_ = false; return false; } uint32_t magic_version = decoder.consume_u32("wasm version"); if (decoder.failed() || magic_version != kWasmVersion) { ok_ = false; return false; } return true; } // Process all sections but the code section. bool ProcessSection(SectionCode section_code, Vector bytes, uint32_t offset) override { ++num_sections_; return true; } bool ProcessCodeSectionHeader(size_t num_functions, uint32_t offset) override { return true; } // Process a function body. bool ProcessFunctionBody(Vector bytes, uint32_t offset) override { ++num_functions_; return true; } void OnFinishedChunk() override {} // Finish the processing of the stream. void OnFinishedStream(std::unique_ptr bytes, size_t length) override { received_bytes_ = std::move(bytes); length_ = length; } // Report an error detected in the StreamingDecoder. void OnError(DecodeResult result) override { ok_ = false; } void OnAbort() override {} size_t num_sections() const { return num_sections_; } size_t num_functions() const { return num_functions_; } bool ok() const { return ok_; } Vector received_bytes() { return Vector(received_bytes_.get(), length_); } private: size_t num_sections_ = 0; size_t num_functions_ = 0; bool ok_ = true; std::unique_ptr received_bytes_; size_t length_; }; class WasmStreamingDecoderTest : public ::testing::Test { public: void ExpectVerifies(Vector data, size_t expected_sections, size_t expected_functions) { for (int split = 0; split <= data.length(); ++split) { // Use a unique_ptr so that the StreamingDecoder can own the processor. std::unique_ptr p(new MockStreamingProcessor()); MockStreamingProcessor* processor = p.get(); StreamingDecoder stream(std::move(p)); stream.OnBytesReceived(data.SubVector(0, split)); stream.OnBytesReceived(data.SubVector(split, data.length())); stream.Finish(); EXPECT_TRUE(processor->ok()); EXPECT_EQ(expected_sections, processor->num_sections()); EXPECT_EQ(expected_functions, processor->num_functions()); EXPECT_EQ(data, processor->received_bytes()); } } void ExpectFailure(Vector data) { for (int split = 0; split <= data.length(); ++split) { std::unique_ptr p(new MockStreamingProcessor()); MockStreamingProcessor* processor = p.get(); StreamingDecoder stream(std::move(p)); stream.OnBytesReceived(data.SubVector(0, split)); stream.OnBytesReceived(data.SubVector(split, data.length())); stream.Finish(); EXPECT_FALSE(processor->ok()); } } }; TEST_F(WasmStreamingDecoderTest, EmptyStream) { std::unique_ptr p(new MockStreamingProcessor()); MockStreamingProcessor* processor = p.get(); StreamingDecoder stream(std::move(p)); stream.Finish(); EXPECT_FALSE(processor->ok()); } TEST_F(WasmStreamingDecoderTest, IncompleteModuleHeader) { const uint8_t data[] = {U32_LE(kWasmMagic), U32_LE(kWasmVersion)}; { std::unique_ptr p(new MockStreamingProcessor()); MockStreamingProcessor* processor = p.get(); StreamingDecoder stream(std::move(p)); stream.OnBytesReceived(Vector(data, 1)); stream.Finish(); EXPECT_FALSE(processor->ok()); } for (int length = 1; length < static_cast(arraysize(data)); ++length) { ExpectFailure(Vector(data, length)); } } TEST_F(WasmStreamingDecoderTest, MagicAndVersion) { const uint8_t data[] = {U32_LE(kWasmMagic), U32_LE(kWasmVersion)}; ExpectVerifies(Vector(data, arraysize(data)), 0, 0); } TEST_F(WasmStreamingDecoderTest, BadMagic) { for (uint32_t x = 1; x; x <<= 1) { const uint8_t data[] = {U32_LE(kWasmMagic ^ x), U32_LE(kWasmVersion)}; ExpectFailure(Vector(data, arraysize(data))); } } TEST_F(WasmStreamingDecoderTest, BadVersion) { for (uint32_t x = 1; x; x <<= 1) { const uint8_t data[] = {U32_LE(kWasmMagic), U32_LE(kWasmVersion ^ x)}; ExpectFailure(Vector(data, arraysize(data))); } } TEST_F(WasmStreamingDecoderTest, OneSection) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x6, // Section Length 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0 // 6 }; ExpectVerifies(Vector(data, arraysize(data)), 1, 0); } TEST_F(WasmStreamingDecoderTest, OneSection_b) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x86, // Section Length = 6 (LEB) 0x0, // -- 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0 // 6 }; ExpectVerifies(Vector(data, arraysize(data)), 1, 0); } TEST_F(WasmStreamingDecoderTest, OneShortSection) { // Short section means that section length + payload is less than 5 bytes, // which is the maximum size of the length field. const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x2, // Section Length 0x0, // Payload 0x0 // 2 }; ExpectVerifies(Vector(data, arraysize(data)), 1, 0); } TEST_F(WasmStreamingDecoderTest, OneShortSection_b) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x82, // Section Length = 2 (LEB) 0x80, // -- 0x0, // -- 0x0, // Payload 0x0 // 2 }; ExpectVerifies(Vector(data, arraysize(data)), 1, 0); } TEST_F(WasmStreamingDecoderTest, OneEmptySection) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x0 // Section Length }; ExpectVerifies(Vector(data, arraysize(data)), 1, 0); } TEST_F(WasmStreamingDecoderTest, OneSectionNotEnoughPayload1) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x6, // Section Length 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0 // 5 }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, OneSectionNotEnoughPayload2) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x6, // Section Length 0x0 // Payload }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, OneSectionInvalidLength) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x80, // Section Length (0 in LEB) 0x80, // -- 0x80, // -- 0x80, // -- 0x80, // -- }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, TwoLongSections) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x6, // Section Length 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x2, // Section ID 0x7, // Section Length 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0 // 7 }; ExpectVerifies(Vector(data, arraysize(data)), 2, 0); } TEST_F(WasmStreamingDecoderTest, TwoShortSections) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x1, // Section Length 0x0, // Payload 0x2, // Section ID 0x2, // Section Length 0x0, // Payload 0x0, // 2 }; ExpectVerifies(Vector(data, arraysize(data)), 2, 0); } TEST_F(WasmStreamingDecoderTest, TwoSectionsShortLong) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x1, // Section Length 0x0, // Payload 0x2, // Section ID 0x7, // Section Length 0x0, // Payload 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0 // 7 }; ExpectVerifies(Vector(data, arraysize(data)), 2, 0); } TEST_F(WasmStreamingDecoderTest, TwoEmptySections) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- 0x1, // Section ID 0x0, // Section Length 0x2, // Section ID 0x0 // Section Length }; ExpectVerifies(Vector(data, arraysize(data)), 2, 0); } TEST_F(WasmStreamingDecoderTest, OneFunction) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x8, // Section Length 0x1, // Number of Functions 0x6, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 }; ExpectVerifies(Vector(data, arraysize(data)), 0, 1); } TEST_F(WasmStreamingDecoderTest, OneShortFunction) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x3, // Section Length 0x1, // Number of Functions 0x1, // Function Length 0x0, // Function }; ExpectVerifies(Vector(data, arraysize(data)), 0, 1); } TEST_F(WasmStreamingDecoderTest, EmptyFunction) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x2, // Section Length 0x1, // Number of Functions 0x0, // Function Length }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, TwoFunctions) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x10, // Section Length 0x2, // Number of Functions 0x6, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 }; ExpectVerifies(Vector(data, arraysize(data)), 0, 2); } TEST_F(WasmStreamingDecoderTest, TwoFunctions_b) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0xb, // Section Length 0x2, // Number of Functions 0x1, // Function Length 0x0, // Function 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 }; ExpectVerifies(Vector(data, arraysize(data)), 0, 2); } TEST_F(WasmStreamingDecoderTest, CodeSectionLengthZero) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x0, // Section Length }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, CodeSectionLengthTooHigh) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0xd, // Section Length 0x2, // Number of Functions 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 0x1, // Function Length 0x0, // Function }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, CodeSectionLengthTooLow) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x9, // Section Length 0x2, // Number of Functions 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 0x1, // Function Length 0x0, // Function }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, CodeSectionLengthTooLowEndsInNumFunctions) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x1, // Section Length 0x82, // Number of Functions 0x80, // -- 0x00, // -- 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 0x1, // Function Length 0x0, // Function }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, CodeSectionLengthTooLowEndsInFunctionLength) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0x5, // Section Length 0x82, // Number of Functions 0x80, // -- 0x00, // -- 0x87, // Function Length 0x80, // -- 0x00, // -- 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 0x1, // Function Length 0x0, // Function }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, NumberOfFunctionsTooHigh) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0xb, // Section Length 0x4, // Number of Functions 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 0x1, // Function Length 0x0, // Function }; ExpectFailure(Vector(data, arraysize(data))); } TEST_F(WasmStreamingDecoderTest, NumberOfFunctionsTooLow) { const uint8_t data[] = { U32_LE(kWasmMagic), // -- U32_LE(kWasmVersion), // -- kCodeSectionCode, // Section ID 0xe, // Section Length 0x2, // Number of Functions 0x1, // Function Length 0x0, // Function 0x2, // Function Length 0x0, // Function 0x0, // 2 0x7, // Function Length 0x0, // Function 0x0, // 2 0x0, // 3 0x0, // 4 0x0, // 5 0x0, // 6 0x0, // 7 }; ExpectFailure(Vector(data, arraysize(data))); } } // namespace wasm } // namespace internal } // namespace v8