Chromium Code Reviews| Index: test/unittests/value-serializer-unittest.cc |
| diff --git a/test/unittests/value-serializer-unittest.cc b/test/unittests/value-serializer-unittest.cc |
| index c0037efb01709e9c401992d89292422494bf18c1..88d931b7d908454d2626e06028c20b49b82532a9 100644 |
| --- a/test/unittests/value-serializer-unittest.cc |
| +++ b/test/unittests/value-serializer-unittest.cc |
| @@ -74,6 +74,9 @@ class ValueSerializerTest : public TestWithIsolate { |
| return deserialization_context_; |
| } |
| + bool AllowInlineWasm() const { return allow_inline_wasm_; } |
| + void SetAllowInlineWasm(bool value) { allow_inline_wasm_ = value; } |
| + |
| // Overridden in more specific fixtures. |
| virtual ValueSerializer::Delegate* GetSerializerDelegate() { return nullptr; } |
| virtual void BeforeEncode(ValueSerializer*) {} |
| @@ -172,6 +175,7 @@ class ValueSerializerTest : public TestWithIsolate { |
| static_cast<int>(data.size()), |
| GetDeserializerDelegate()); |
| deserializer.SetSupportsLegacyWireFormat(true); |
| + deserializer.SetAllowInlineWasm(AllowInlineWasm()); |
| BeforeDecode(&deserializer); |
| ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); |
| Local<Value> result; |
| @@ -196,6 +200,7 @@ class ValueSerializerTest : public TestWithIsolate { |
| static_cast<int>(data.size()), |
| GetDeserializerDelegate()); |
| deserializer.SetSupportsLegacyWireFormat(true); |
| + deserializer.SetAllowInlineWasm(AllowInlineWasm()); |
| BeforeDecode(&deserializer); |
| ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); |
| ASSERT_EQ(0u, deserializer.GetWireFormatVersion()); |
| @@ -219,6 +224,7 @@ class ValueSerializerTest : public TestWithIsolate { |
| static_cast<int>(data.size()), |
| GetDeserializerDelegate()); |
| deserializer.SetSupportsLegacyWireFormat(true); |
| + deserializer.SetAllowInlineWasm(AllowInlineWasm()); |
| BeforeDecode(&deserializer); |
| Maybe<bool> header_result = deserializer.ReadHeader(context); |
| if (header_result.IsNothing()) { |
| @@ -275,6 +281,7 @@ class ValueSerializerTest : public TestWithIsolate { |
| Local<Context> deserialization_context_; |
| Local<FunctionTemplate> host_object_constructor_template_; |
| i::Isolate* isolate_; |
| + bool allow_inline_wasm_ = false; |
| DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest); |
| }; |
| @@ -2594,7 +2601,38 @@ TEST_F(ValueSerializerTestWithHostArrayBufferView, RoundTripUint8ArrayInput) { |
| // mostly checks that the logic to embed it in structured clone serialization |
| // works correctly. |
| +// A simple module which exports an "increment" function. |
| +// Copied from test/mjsunit/wasm/incrementer.wasm. |
| +const unsigned char kIncrementerWasm[] = { |
| + 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127, |
| + 3, 2, 1, 0, 7, 13, 1, 9, 105, 110, 99, 114, 101, 109, 101, 110, |
| + 116, 0, 0, 10, 9, 1, 7, 0, 32, 0, 65, 1, 106, 11, |
| +}; |
| + |
| class ValueSerializerTestWithWasm : public ValueSerializerTest { |
| + public: |
| + ValueSerializerTestWithWasm() : serialize_delegate_(&transfer_modules_) {} |
| + |
| + void Reset() { |
| + current_serializer_delegate_ = nullptr; |
| + transfer_modules_.clear(); |
| + SetAllowInlineWasm(false); |
| + } |
| + |
| + void EnableTransferSerialization() { |
| + current_serializer_delegate_ = &serialize_delegate_; |
| + } |
| + |
| + void BeforeDecode(ValueDeserializer* deserializer) override { |
| + for (uint32_t i = 0; i < static_cast<uint32_t>(transfer_modules_.size()); |
| + ++i) { |
| + deserializer->TransferWasmCompiledModule( |
| + i, WasmCompiledModule::FromTransferrableModule(isolate(), |
| + transfer_modules_[i]) |
| + .ToLocalChecked()); |
| + } |
| + } |
| + |
| protected: |
| static void SetUpTestCase() { |
| g_saved_flag = i::FLAG_expose_wasm; |
| @@ -2608,32 +2646,170 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { |
| g_saved_flag = false; |
| } |
| + class SerializeToTransfer : public ValueSerializer::Delegate { |
| + public: |
| + SerializeToTransfer( |
| + std::vector<WasmCompiledModule::TransferrableModule>* modules) |
| + : modules_(modules) {} |
| + Maybe<uint32_t> GetWasmModuleTransferId( |
| + Isolate* isolate, Local<WasmCompiledModule> module) override { |
| + modules_->push_back(module->GetTransferrableModule()); |
| + return Just(static_cast<uint32_t>(modules_->size()) - 1); |
| + } |
| + |
| + void ThrowDataCloneError(Local<String> message) override {} |
|
jbroman
2017/03/17 14:44:37
Are you expecting this to be unreached? (If so, NO
Mircea Trofin
2017/03/17 16:55:31
Done.
|
| + |
| + private: |
| + std::vector<WasmCompiledModule::TransferrableModule>* modules_; |
| + }; |
| + |
| + ValueSerializer::Delegate* GetSerializerDelegate() override { |
| + return current_serializer_delegate_; |
| + } |
| + |
| + Local<WasmCompiledModule> MakeWasm() { |
| + return WasmCompiledModule::DeserializeOrCompile( |
| + isolate(), {nullptr, 0}, |
| + {kIncrementerWasm, sizeof(kIncrementerWasm)}) |
| + .ToLocalChecked(); |
| + } |
| + |
| + void ExpectPass() { |
| + RoundTripTest( |
| + [this]() { return MakeWasm(); }, |
| + [this](Local<Value> value) { |
| + ASSERT_TRUE(value->IsWebAssemblyCompiledModule()); |
| + EXPECT_TRUE(EvaluateScriptForResultBool( |
| + "new WebAssembly.Instance(result).exports.increment(8) === 9")); |
| + }); |
| + } |
| + |
| + void ExpectFail() { |
| + EncodeTest( |
| + [this]() { return MakeWasm(); }, |
| + [this](const std::vector<uint8_t>& data) { InvalidDecodeTest(data); }); |
| + } |
| + |
| + Local<Value> GetComplexObjectWithDuplicate() { |
| + Local<Value> wasm_module = MakeWasm(); |
| + serialization_context() |
| + ->Global() |
| + ->CreateDataProperty(serialization_context(), |
| + StringFromUtf8("wasm_module"), wasm_module) |
| + .FromMaybe(false); |
| + Local<Script> script = |
| + Script::Compile( |
| + serialization_context(), |
| + StringFromUtf8("({mod1: wasm_module, num: 2, mod2: wasm_module})")) |
| + .ToLocalChecked(); |
| + return script->Run(serialization_context()).ToLocalChecked(); |
| + } |
| + |
| + void VerifyComplexObject(Local<Value> value) { |
| + ASSERT_TRUE(value->IsObject()); |
| + EXPECT_TRUE(EvaluateScriptForResultBool( |
| + "result.mod1 instanceof WebAssembly.Module")); |
| + EXPECT_TRUE(EvaluateScriptForResultBool( |
| + "result.mod2 instanceof WebAssembly.Module")); |
| + EXPECT_TRUE(EvaluateScriptForResultBool("result.num === 2")); |
| + } |
| + |
| + Local<Value> GetComplexObjectWithMany() { |
| + Local<Value> wasm_module1 = MakeWasm(); |
| + Local<Value> wasm_module2 = MakeWasm(); |
| + serialization_context() |
| + ->Global() |
| + ->CreateDataProperty(serialization_context(), |
| + StringFromUtf8("wasm_module1"), wasm_module1) |
| + .FromMaybe(false); |
| + serialization_context() |
| + ->Global() |
| + ->CreateDataProperty(serialization_context(), |
| + StringFromUtf8("wasm_module2"), wasm_module2) |
| + .FromMaybe(false); |
| + Local<Script> script = |
| + Script::Compile( |
| + serialization_context(), |
| + StringFromUtf8( |
| + "({mod1: wasm_module1, num: 2, mod2: wasm_module2})")) |
| + .ToLocalChecked(); |
| + return script->Run(serialization_context()).ToLocalChecked(); |
| + } |
| + |
| private: |
| static bool g_saved_flag; |
| + std::vector<WasmCompiledModule::TransferrableModule> transfer_modules_; |
| + SerializeToTransfer serialize_delegate_; |
| + ValueSerializer::Delegate* current_serializer_delegate_ = nullptr; |
| }; |
| bool ValueSerializerTestWithWasm::g_saved_flag = false; |
| -// A simple module which exports an "increment" function. |
| -// Copied from test/mjsunit/wasm/incrementer.wasm. |
| -const unsigned char kIncrementerWasm[] = { |
| - 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127, |
| - 3, 2, 1, 0, 7, 13, 1, 9, 105, 110, 99, 114, 101, 109, 101, 110, |
| - 116, 0, 0, 10, 9, 1, 7, 0, 32, 0, 65, 1, 106, 11, |
| -}; |
| +// We only want to allow deserialization through |
| +// transferred modules - which requres both serializer |
| +// and deserializer to understand that - or through |
| +// explicitly allowing inlined data, which requires |
| +// deserializer opt-in (we default the serializer to |
| +// inlined data because we don't trust that data on the |
| +// receiving end anyway). |
| + |
| +TEST_F(ValueSerializerTestWithWasm, RoundtripWasmTransfer) { |
| + EnableTransferSerialization(); |
| + ExpectPass(); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, RountripWasmInline) { |
| + SetAllowInlineWasm(true); |
| + ExpectPass(); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, CannotDeserializeWasmInlineData) { |
| + ExpectFail(); |
| +} |
| -TEST_F(ValueSerializerTestWithWasm, RoundTripWasmModule) { |
| +TEST_F(ValueSerializerTestWithWasm, CannotTransferWasmWhenExpectingInline) { |
| + EnableTransferSerialization(); |
| + SetAllowInlineWasm(true); |
| + ExpectFail(); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateTransfer) { |
| + EnableTransferSerialization(); |
| RoundTripTest( |
| - [this]() { |
| - return WasmCompiledModule::DeserializeOrCompile( |
| - isolate(), {nullptr, 0}, |
| - {kIncrementerWasm, sizeof(kIncrementerWasm)}) |
| - .ToLocalChecked(); |
| - }, |
| + [this]() { return GetComplexObjectWithDuplicate(); }, |
| [this](Local<Value> value) { |
| - ASSERT_TRUE(value->IsWebAssemblyCompiledModule()); |
| - EXPECT_TRUE(EvaluateScriptForResultBool( |
| - "new WebAssembly.Instance(result).exports.increment(8) === 9")); |
| + VerifyComplexObject(value); |
| + EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 === result.mod2")); |
| + }); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateInline) { |
| + SetAllowInlineWasm(true); |
| + RoundTripTest( |
| + [this]() { return GetComplexObjectWithDuplicate(); }, |
| + [this](Local<Value> value) { |
| + VerifyComplexObject(value); |
| + EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 === result.mod2")); |
| + }); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyTransfer) { |
| + EnableTransferSerialization(); |
| + RoundTripTest( |
| + [this]() { return GetComplexObjectWithMany(); }, |
| + [this](Local<Value> value) { |
| + VerifyComplexObject(value); |
| + EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 != result.mod2")); |
| + }); |
| +} |
| + |
| +TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyInline) { |
| + SetAllowInlineWasm(true); |
| + RoundTripTest( |
| + [this]() { return GetComplexObjectWithMany(); }, |
| + [this](Local<Value> value) { |
| + VerifyComplexObject(value); |
| + EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 != result.mod2")); |
| }); |
| } |