Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/value-serializer.h"
6 :
7 : #include <algorithm>
8 : #include <string>
9 :
10 : #include "include/v8.h"
11 : #include "src/api-inl.h"
12 : #include "src/base/build_config.h"
13 : #include "src/objects-inl.h"
14 : #include "src/wasm/wasm-objects.h"
15 : #include "test/unittests/test-utils.h"
16 : #include "testing/gmock/include/gmock/gmock.h"
17 : #include "testing/gtest/include/gtest/gtest.h"
18 :
19 : namespace v8 {
20 : namespace {
21 :
22 : using ::testing::_;
23 : using ::testing::Invoke;
24 : using ::testing::Return;
25 :
26 : class ValueSerializerTest : public TestWithIsolate {
27 : protected:
28 83 : ValueSerializerTest()
29 83 : : serialization_context_(Context::New(isolate())),
30 332 : deserialization_context_(Context::New(isolate())) {
31 : // Create a host object type that can be tested through
32 : // serialization/deserialization delegates below.
33 : Local<FunctionTemplate> function_template = v8::FunctionTemplate::New(
34 52 : isolate(), [](const FunctionCallbackInfo<Value>& args) {
35 26 : args.Holder()->SetInternalField(0, args[0]);
36 26 : args.Holder()->SetInternalField(1, args[1]);
37 135 : });
38 166 : function_template->InstanceTemplate()->SetInternalFieldCount(2);
39 166 : function_template->InstanceTemplate()->SetAccessor(
40 : StringFromUtf8("value"),
41 16 : [](Local<String> property, const PropertyCallbackInfo<Value>& args) {
42 : args.GetReturnValue().Set(args.Holder()->GetInternalField(0));
43 99 : });
44 166 : function_template->InstanceTemplate()->SetAccessor(
45 : StringFromUtf8("value2"),
46 4 : [](Local<String> property, const PropertyCallbackInfo<Value>& args) {
47 : args.GetReturnValue().Set(args.Holder()->GetInternalField(1));
48 87 : });
49 415 : for (Local<Context> context :
50 249 : {serialization_context_, deserialization_context_}) {
51 332 : context->Global()
52 332 : ->CreateDataProperty(
53 : context, StringFromUtf8("ExampleHostObject"),
54 498 : function_template->GetFunction(context).ToLocalChecked())
55 : .ToChecked();
56 : }
57 83 : host_object_constructor_template_ = function_template;
58 83 : isolate_ = reinterpret_cast<i::Isolate*>(isolate());
59 83 : }
60 :
61 166 : ~ValueSerializerTest() override {
62 : // In some cases unhandled scheduled exceptions from current test produce
63 : // that Context::New(isolate()) from next test's constructor returns NULL.
64 : // In order to prevent that, we added destructor which will clear scheduled
65 : // exceptions just for the current test from test case.
66 166 : if (isolate_->has_scheduled_exception()) {
67 : isolate_->clear_scheduled_exception();
68 : }
69 : }
70 :
71 : const Local<Context>& serialization_context() {
72 16 : return serialization_context_;
73 : }
74 : const Local<Context>& deserialization_context() {
75 11 : return deserialization_context_;
76 : }
77 :
78 : bool ExpectInlineWasm() const { return expect_inline_wasm_; }
79 4 : void SetExpectInlineWasm(bool value) { expect_inline_wasm_ = value; }
80 :
81 : // Overridden in more specific fixtures.
82 222 : virtual ValueSerializer::Delegate* GetSerializerDelegate() { return nullptr; }
83 125 : virtual void BeforeEncode(ValueSerializer*) {}
84 235 : virtual ValueDeserializer::Delegate* GetDeserializerDelegate() {
85 235 : return nullptr;
86 : }
87 248 : virtual void BeforeDecode(ValueDeserializer*) {}
88 :
89 127 : Local<Value> RoundTripTest(Local<Value> input_value) {
90 127 : std::vector<uint8_t> encoded = EncodeTest(input_value);
91 254 : return DecodeTest(encoded);
92 : }
93 :
94 : // Variant for the common case where a script is used to build the original
95 : // value.
96 : Local<Value> RoundTripTest(const char* source) {
97 97 : return RoundTripTest(EvaluateScriptForInput(source));
98 : }
99 :
100 : // Variant which uses JSON.parse/stringify to check the result.
101 2 : void RoundTripJSON(const char* source) {
102 : Local<Value> input_value =
103 2 : JSON::Parse(serialization_context_, StringFromUtf8(source))
104 2 : .ToLocalChecked();
105 2 : Local<Value> result = RoundTripTest(input_value);
106 4 : ASSERT_TRUE(result->IsObject());
107 6 : EXPECT_EQ(source, Utf8Value(JSON::Stringify(deserialization_context_,
108 : result.As<Object>())
109 0 : .ToLocalChecked()));
110 : }
111 :
112 141 : Maybe<std::vector<uint8_t>> DoEncode(Local<Value> value) {
113 141 : Local<Context> context = serialization_context();
114 423 : ValueSerializer serializer(isolate(), GetSerializerDelegate());
115 141 : BeforeEncode(&serializer);
116 141 : serializer.WriteHeader();
117 282 : if (!serializer.WriteValue(context, value).FromMaybe(false)) {
118 : return Nothing<std::vector<uint8_t>>();
119 : }
120 132 : std::pair<uint8_t*, size_t> buffer = serializer.Release();
121 132 : std::vector<uint8_t> result(buffer.first, buffer.first + buffer.second);
122 132 : if (auto* delegate = GetSerializerDelegate())
123 20 : delegate->FreeBufferMemory(buffer.first);
124 : else
125 112 : free(buffer.first);
126 : return Just(std::move(result));
127 : }
128 :
129 132 : std::vector<uint8_t> EncodeTest(Local<Value> input_value) {
130 : Context::Scope scope(serialization_context());
131 264 : TryCatch try_catch(isolate());
132 : std::vector<uint8_t> buffer;
133 : // Ideally we would use GTest's ASSERT_* macros here and below. However,
134 : // those only work in functions returning {void}, and they only terminate
135 : // the current function, but not the entire current test (so we would need
136 : // additional manual checks whether it is okay to proceed). Given that our
137 : // test driver starts a new process for each test anyway, it is acceptable
138 : // to just use a CHECK (which would kill the process on failure) instead.
139 396 : CHECK(DoEncode(input_value).To(&buffer));
140 132 : CHECK(!try_catch.HasCaught());
141 132 : return buffer;
142 : }
143 :
144 : std::vector<uint8_t> EncodeTest(const char* source) {
145 1 : return EncodeTest(EvaluateScriptForInput(source));
146 : }
147 :
148 9 : v8::Local<v8::Message> InvalidEncodeTest(Local<Value> input_value) {
149 : Context::Scope scope(serialization_context());
150 18 : TryCatch try_catch(isolate());
151 27 : CHECK(DoEncode(input_value).IsNothing());
152 18 : return try_catch.Message();
153 : }
154 :
155 : v8::Local<v8::Message> InvalidEncodeTest(const char* source) {
156 7 : return InvalidEncodeTest(EvaluateScriptForInput(source));
157 : }
158 :
159 224 : Local<Value> DecodeTest(const std::vector<uint8_t>& data) {
160 224 : Local<Context> context = deserialization_context();
161 : Context::Scope scope(context);
162 448 : TryCatch try_catch(isolate());
163 : ValueDeserializer deserializer(isolate(), &data[0],
164 : static_cast<int>(data.size()),
165 896 : GetDeserializerDelegate());
166 224 : deserializer.SetSupportsLegacyWireFormat(true);
167 224 : deserializer.SetExpectInlineWasm(ExpectInlineWasm());
168 224 : BeforeDecode(&deserializer);
169 448 : CHECK(deserializer.ReadHeader(context).FromMaybe(false));
170 : Local<Value> result;
171 448 : CHECK(deserializer.ReadValue(context).ToLocal(&result));
172 224 : CHECK(!result.IsEmpty());
173 224 : CHECK(!try_catch.HasCaught());
174 896 : CHECK(context->Global()
175 : ->CreateDataProperty(context, StringFromUtf8("result"), result)
176 : .FromMaybe(false));
177 224 : CHECK(!try_catch.HasCaught());
178 448 : return result;
179 : }
180 :
181 8 : Local<Value> DecodeTestForVersion0(const std::vector<uint8_t>& data) {
182 8 : Local<Context> context = deserialization_context();
183 : Context::Scope scope(context);
184 16 : TryCatch try_catch(isolate());
185 : ValueDeserializer deserializer(isolate(), &data[0],
186 : static_cast<int>(data.size()),
187 32 : GetDeserializerDelegate());
188 8 : deserializer.SetSupportsLegacyWireFormat(true);
189 8 : deserializer.SetExpectInlineWasm(ExpectInlineWasm());
190 8 : BeforeDecode(&deserializer);
191 16 : CHECK(deserializer.ReadHeader(context).FromMaybe(false));
192 8 : CHECK_EQ(0u, deserializer.GetWireFormatVersion());
193 : Local<Value> result;
194 16 : CHECK(deserializer.ReadValue(context).ToLocal(&result));
195 8 : CHECK(!result.IsEmpty());
196 8 : CHECK(!try_catch.HasCaught());
197 32 : CHECK(context->Global()
198 : ->CreateDataProperty(context, StringFromUtf8("result"), result)
199 : .FromMaybe(false));
200 8 : CHECK(!try_catch.HasCaught());
201 16 : return result;
202 : }
203 :
204 30 : void InvalidDecodeTest(const std::vector<uint8_t>& data) {
205 30 : Local<Context> context = deserialization_context();
206 : Context::Scope scope(context);
207 58 : TryCatch try_catch(isolate());
208 : ValueDeserializer deserializer(isolate(), &data[0],
209 : static_cast<int>(data.size()),
210 118 : GetDeserializerDelegate());
211 30 : deserializer.SetSupportsLegacyWireFormat(true);
212 30 : deserializer.SetExpectInlineWasm(ExpectInlineWasm());
213 30 : BeforeDecode(&deserializer);
214 30 : Maybe<bool> header_result = deserializer.ReadHeader(context);
215 30 : if (header_result.IsNothing()) {
216 4 : EXPECT_TRUE(try_catch.HasCaught());
217 2 : return;
218 : }
219 28 : CHECK(header_result.ToChecked());
220 56 : CHECK(deserializer.ReadValue(context).IsEmpty());
221 56 : EXPECT_TRUE(try_catch.HasCaught());
222 : }
223 :
224 108 : Local<Value> EvaluateScriptForInput(const char* utf8_source) {
225 : Context::Scope scope(serialization_context_);
226 108 : Local<String> source = StringFromUtf8(utf8_source);
227 : Local<Script> script =
228 108 : Script::Compile(serialization_context_, source).ToLocalChecked();
229 216 : return script->Run(serialization_context_).ToLocalChecked();
230 : }
231 :
232 327 : void ExpectScriptTrue(const char* utf8_source) {
233 : Context::Scope scope(deserialization_context_);
234 327 : Local<String> source = StringFromUtf8(utf8_source);
235 : Local<Script> script =
236 327 : Script::Compile(deserialization_context_, source).ToLocalChecked();
237 327 : Local<Value> value = script->Run(deserialization_context_).ToLocalChecked();
238 654 : EXPECT_TRUE(value->BooleanValue(isolate()));
239 327 : }
240 :
241 1019 : Local<String> StringFromUtf8(const char* source) {
242 1019 : return String::NewFromUtf8(isolate(), source, NewStringType::kNormal)
243 1019 : .ToLocalChecked();
244 : }
245 :
246 14 : std::string Utf8Value(Local<Value> value) {
247 28 : String::Utf8Value utf8(isolate(), value);
248 28 : return std::string(*utf8, utf8.length());
249 : }
250 :
251 11 : Local<Object> NewHostObject(Local<Context> context, int argc,
252 : Local<Value> argv[]) {
253 11 : return host_object_constructor_template_->GetFunction(context)
254 : .ToLocalChecked()
255 11 : ->NewInstance(context, argc, argv)
256 11 : .ToLocalChecked();
257 : }
258 :
259 1 : Local<Object> NewDummyUint8Array() {
260 : static uint8_t data[] = {4, 5, 6};
261 : Local<ArrayBuffer> ab =
262 1 : ArrayBuffer::New(isolate(), static_cast<void*>(data), sizeof(data));
263 1 : return Uint8Array::New(ab, 0, sizeof(data));
264 : }
265 :
266 : private:
267 : Local<Context> serialization_context_;
268 : Local<Context> deserialization_context_;
269 : Local<FunctionTemplate> host_object_constructor_template_;
270 : i::Isolate* isolate_;
271 : bool expect_inline_wasm_ = false;
272 :
273 : DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest);
274 : };
275 :
276 15444 : TEST_F(ValueSerializerTest, DecodeInvalid) {
277 : // Version tag but no content.
278 2 : InvalidDecodeTest({0xFF});
279 : // Version too large.
280 2 : InvalidDecodeTest({0xFF, 0x7F, 0x5F});
281 : // Nonsense tag.
282 2 : InvalidDecodeTest({0xFF, 0x09, 0xDD});
283 1 : }
284 :
285 15444 : TEST_F(ValueSerializerTest, RoundTripOddball) {
286 1 : Local<Value> value = RoundTripTest(Undefined(isolate()));
287 1 : EXPECT_TRUE(value->IsUndefined());
288 1 : value = RoundTripTest(True(isolate()));
289 2 : EXPECT_TRUE(value->IsTrue());
290 1 : value = RoundTripTest(False(isolate()));
291 2 : EXPECT_TRUE(value->IsFalse());
292 1 : value = RoundTripTest(Null(isolate()));
293 1 : EXPECT_TRUE(value->IsNull());
294 1 : }
295 :
296 15444 : TEST_F(ValueSerializerTest, DecodeOddball) {
297 : // What this code is expected to generate.
298 2 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x5F});
299 1 : EXPECT_TRUE(value->IsUndefined());
300 2 : value = DecodeTest({0xFF, 0x09, 0x54});
301 2 : EXPECT_TRUE(value->IsTrue());
302 2 : value = DecodeTest({0xFF, 0x09, 0x46});
303 2 : EXPECT_TRUE(value->IsFalse());
304 2 : value = DecodeTest({0xFF, 0x09, 0x30});
305 1 : EXPECT_TRUE(value->IsNull());
306 :
307 : // What v9 of the Blink code generates.
308 2 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x5F, 0x00});
309 1 : EXPECT_TRUE(value->IsUndefined());
310 2 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x54, 0x00});
311 2 : EXPECT_TRUE(value->IsTrue());
312 2 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x46, 0x00});
313 2 : EXPECT_TRUE(value->IsFalse());
314 2 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x30, 0x00});
315 1 : EXPECT_TRUE(value->IsNull());
316 :
317 : // v0 (with no explicit version).
318 2 : value = DecodeTest({0x5F, 0x00});
319 1 : EXPECT_TRUE(value->IsUndefined());
320 2 : value = DecodeTest({0x54, 0x00});
321 2 : EXPECT_TRUE(value->IsTrue());
322 2 : value = DecodeTest({0x46, 0x00});
323 2 : EXPECT_TRUE(value->IsFalse());
324 2 : value = DecodeTest({0x30, 0x00});
325 1 : EXPECT_TRUE(value->IsNull());
326 1 : }
327 :
328 15444 : TEST_F(ValueSerializerTest, EncodeArrayStackOverflow) {
329 1 : InvalidEncodeTest("var a = []; for (var i = 0; i < 1E5; i++) a = [a]; a");
330 1 : }
331 :
332 15444 : TEST_F(ValueSerializerTest, EncodeObjectStackOverflow) {
333 1 : InvalidEncodeTest("var a = {}; for (var i = 0; i < 1E5; i++) a = {a}; a");
334 1 : }
335 :
336 15444 : TEST_F(ValueSerializerTest, DecodeArrayStackOverflow) {
337 : static const int nesting_level = 1E5;
338 : std::vector<uint8_t> payload;
339 : // Header.
340 2 : payload.push_back(0xFF);
341 2 : payload.push_back(0x0D);
342 :
343 : // Nested arrays, each with one element.
344 200001 : for (int i = 0; i < nesting_level; i++) {
345 200000 : payload.push_back(0x41);
346 200000 : payload.push_back(0x01);
347 : }
348 :
349 : // Innermost array is empty.
350 2 : payload.push_back(0x41);
351 2 : payload.push_back(0x00);
352 2 : payload.push_back(0x24);
353 2 : payload.push_back(0x00);
354 2 : payload.push_back(0x00);
355 :
356 : // Close nesting.
357 200001 : for (int i = 0; i < nesting_level; i++) {
358 200000 : payload.push_back(0x24);
359 200000 : payload.push_back(0x00);
360 200000 : payload.push_back(0x01);
361 : }
362 :
363 1 : InvalidDecodeTest(payload);
364 1 : }
365 :
366 15444 : TEST_F(ValueSerializerTest, DecodeObjectStackOverflow) {
367 : static const int nesting_level = 1E5;
368 : std::vector<uint8_t> payload;
369 : // Header.
370 2 : payload.push_back(0xFF);
371 2 : payload.push_back(0x0D);
372 :
373 : // Nested objects, each with one property 'a'.
374 200001 : for (int i = 0; i < nesting_level; i++) {
375 200000 : payload.push_back(0x6F);
376 200000 : payload.push_back(0x22);
377 200000 : payload.push_back(0x01);
378 200000 : payload.push_back(0x61);
379 : }
380 :
381 : // Innermost array is empty.
382 2 : payload.push_back(0x6F);
383 2 : payload.push_back(0x7B);
384 2 : payload.push_back(0x00);
385 :
386 : // Close nesting.
387 200001 : for (int i = 0; i < nesting_level; i++) {
388 200000 : payload.push_back(0x7B);
389 200000 : payload.push_back(0x01);
390 : }
391 :
392 1 : InvalidDecodeTest(payload);
393 1 : }
394 :
395 15444 : TEST_F(ValueSerializerTest, DecodeVerifyObjectCount) {
396 : static const int nesting_level = 1E5;
397 : std::vector<uint8_t> payload;
398 : // Header.
399 2 : payload.push_back(0xFF);
400 2 : payload.push_back(0x0D);
401 :
402 : // Repeat SerializationTag:kVerifyObjectCount. This leads to stack overflow.
403 200001 : for (int i = 0; i < nesting_level; i++) {
404 200000 : payload.push_back(0x3F);
405 200000 : payload.push_back(0x01);
406 : }
407 :
408 1 : InvalidDecodeTest(payload);
409 1 : }
410 :
411 15444 : TEST_F(ValueSerializerTest, RoundTripNumber) {
412 2 : Local<Value> value = RoundTripTest(Integer::New(isolate(), 42));
413 2 : ASSERT_TRUE(value->IsInt32());
414 2 : EXPECT_EQ(42, Int32::Cast(*value)->Value());
415 :
416 2 : value = RoundTripTest(Integer::New(isolate(), -31337));
417 2 : ASSERT_TRUE(value->IsInt32());
418 2 : EXPECT_EQ(-31337, Int32::Cast(*value)->Value());
419 :
420 : value = RoundTripTest(
421 2 : Integer::New(isolate(), std::numeric_limits<int32_t>::min()));
422 2 : ASSERT_TRUE(value->IsInt32());
423 2 : EXPECT_EQ(std::numeric_limits<int32_t>::min(), Int32::Cast(*value)->Value());
424 :
425 2 : value = RoundTripTest(Number::New(isolate(), -0.25));
426 2 : ASSERT_TRUE(value->IsNumber());
427 2 : EXPECT_EQ(-0.25, Number::Cast(*value)->Value());
428 :
429 : value = RoundTripTest(
430 2 : Number::New(isolate(), std::numeric_limits<double>::quiet_NaN()));
431 2 : ASSERT_TRUE(value->IsNumber());
432 2 : EXPECT_TRUE(std::isnan(Number::Cast(*value)->Value()));
433 : }
434 :
435 15444 : TEST_F(ValueSerializerTest, DecodeNumber) {
436 : // 42 zig-zag encoded (signed)
437 2 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x49, 0x54});
438 2 : ASSERT_TRUE(value->IsInt32());
439 2 : EXPECT_EQ(42, Int32::Cast(*value)->Value());
440 :
441 : // 42 varint encoded (unsigned)
442 2 : value = DecodeTest({0xFF, 0x09, 0x55, 0x2A});
443 2 : ASSERT_TRUE(value->IsInt32());
444 2 : EXPECT_EQ(42, Int32::Cast(*value)->Value());
445 :
446 : // 160 zig-zag encoded (signed)
447 2 : value = DecodeTest({0xFF, 0x09, 0x49, 0xC0, 0x02});
448 2 : ASSERT_TRUE(value->IsInt32());
449 2 : ASSERT_EQ(160, Int32::Cast(*value)->Value());
450 :
451 : // 160 varint encoded (unsigned)
452 2 : value = DecodeTest({0xFF, 0x09, 0x55, 0xA0, 0x01});
453 2 : ASSERT_TRUE(value->IsInt32());
454 2 : ASSERT_EQ(160, Int32::Cast(*value)->Value());
455 :
456 : #if defined(V8_TARGET_LITTLE_ENDIAN)
457 : // IEEE 754 doubles, little-endian byte order
458 : value = DecodeTest(
459 2 : {0xFF, 0x09, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xBF});
460 2 : ASSERT_TRUE(value->IsNumber());
461 2 : EXPECT_EQ(-0.25, Number::Cast(*value)->Value());
462 :
463 : // quiet NaN
464 : value = DecodeTest(
465 2 : {0xFF, 0x09, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F});
466 2 : ASSERT_TRUE(value->IsNumber());
467 2 : EXPECT_TRUE(std::isnan(Number::Cast(*value)->Value()));
468 :
469 : // signaling NaN
470 : value = DecodeTest(
471 2 : {0xFF, 0x09, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x7F});
472 2 : ASSERT_TRUE(value->IsNumber());
473 2 : EXPECT_TRUE(std::isnan(Number::Cast(*value)->Value()));
474 : #endif
475 : // TODO(jbroman): Equivalent test for big-endian machines.
476 : }
477 :
478 15444 : TEST_F(ValueSerializerTest, RoundTripBigInt) {
479 2 : Local<Value> value = RoundTripTest(BigInt::New(isolate(), -42));
480 2 : ASSERT_TRUE(value->IsBigInt());
481 1 : ExpectScriptTrue("result === -42n");
482 :
483 2 : value = RoundTripTest(BigInt::New(isolate(), 42));
484 1 : ExpectScriptTrue("result === 42n");
485 :
486 2 : value = RoundTripTest(BigInt::New(isolate(), 0));
487 1 : ExpectScriptTrue("result === 0n");
488 :
489 : value = RoundTripTest("0x1234567890abcdef777888999n");
490 1 : ExpectScriptTrue("result === 0x1234567890abcdef777888999n");
491 :
492 : value = RoundTripTest("-0x1234567890abcdef777888999123n");
493 1 : ExpectScriptTrue("result === -0x1234567890abcdef777888999123n");
494 :
495 : Context::Scope scope(serialization_context());
496 1 : value = RoundTripTest(BigIntObject::New(isolate(), 23));
497 2 : ASSERT_TRUE(value->IsBigIntObject());
498 1 : ExpectScriptTrue("result == 23n");
499 : }
500 :
501 15444 : TEST_F(ValueSerializerTest, DecodeBigInt) {
502 : Local<Value> value = DecodeTest({
503 : 0xFF, 0x0D, // Version 13
504 : 0x5A, // BigInt
505 : 0x08, // Bitfield: sign = false, bytelength = 4
506 : 0x2A, 0x00, 0x00, 0x00, // Digit: 42
507 2 : });
508 2 : ASSERT_TRUE(value->IsBigInt());
509 1 : ExpectScriptTrue("result === 42n");
510 :
511 : value = DecodeTest({
512 : 0xFF, 0x0D, // Version 13
513 : 0x7A, // BigIntObject
514 : 0x11, // Bitfield: sign = true, bytelength = 8
515 : 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Digit: 42
516 2 : });
517 2 : ASSERT_TRUE(value->IsBigIntObject());
518 1 : ExpectScriptTrue("result == -42n");
519 :
520 : value = DecodeTest({
521 : 0xFF, 0x0D, // Version 13
522 : 0x5A, // BigInt
523 : 0x10, // Bitfield: sign = false, bytelength = 8
524 : 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12 // Digit(s).
525 2 : });
526 1 : ExpectScriptTrue("result === 0x1234567890abcdefn");
527 :
528 : value = DecodeTest({0xFF, 0x0D, // Version 13
529 : 0x5A, // BigInt
530 : 0x17, // Bitfield: sign = true, bytelength = 11
531 : 0xEF, 0xCD, 0xAB, 0x90, // Digits.
532 2 : 0x78, 0x56, 0x34, 0x12, 0x33, 0x44, 0x55});
533 1 : ExpectScriptTrue("result === -0x5544331234567890abcdefn");
534 :
535 : value = DecodeTest({
536 : 0xFF, 0x0D, // Version 13
537 : 0x5A, // BigInt
538 : 0x02, // Bitfield: sign = false, bytelength = 1
539 : 0x2A, // Digit: 42
540 2 : });
541 1 : ExpectScriptTrue("result === 42n");
542 : }
543 :
544 : // String constants (in UTF-8) used for string encoding tests.
545 : static const char kHelloString[] = "Hello";
546 : static const char kQuebecString[] = "\x51\x75\xC3\xA9\x62\x65\x63";
547 : static const char kEmojiString[] = "\xF0\x9F\x91\x8A";
548 :
549 15444 : TEST_F(ValueSerializerTest, RoundTripString) {
550 1 : Local<Value> value = RoundTripTest(String::Empty(isolate()));
551 1 : ASSERT_TRUE(value->IsString());
552 2 : EXPECT_EQ(0, String::Cast(*value)->Length());
553 :
554 : // Inside ASCII.
555 2 : value = RoundTripTest(StringFromUtf8(kHelloString));
556 1 : ASSERT_TRUE(value->IsString());
557 2 : EXPECT_EQ(5, String::Cast(*value)->Length());
558 2 : EXPECT_EQ(kHelloString, Utf8Value(value));
559 :
560 : // Inside Latin-1 (i.e. one-byte string), but not ASCII.
561 2 : value = RoundTripTest(StringFromUtf8(kQuebecString));
562 1 : ASSERT_TRUE(value->IsString());
563 2 : EXPECT_EQ(6, String::Cast(*value)->Length());
564 2 : EXPECT_EQ(kQuebecString, Utf8Value(value));
565 :
566 : // An emoji (decodes to two 16-bit chars).
567 2 : value = RoundTripTest(StringFromUtf8(kEmojiString));
568 1 : ASSERT_TRUE(value->IsString());
569 2 : EXPECT_EQ(2, String::Cast(*value)->Length());
570 2 : EXPECT_EQ(kEmojiString, Utf8Value(value));
571 : }
572 :
573 15444 : TEST_F(ValueSerializerTest, DecodeString) {
574 : // Decoding the strings above from UTF-8.
575 2 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x53, 0x00});
576 1 : ASSERT_TRUE(value->IsString());
577 2 : EXPECT_EQ(0, String::Cast(*value)->Length());
578 :
579 2 : value = DecodeTest({0xFF, 0x09, 0x53, 0x05, 'H', 'e', 'l', 'l', 'o'});
580 1 : ASSERT_TRUE(value->IsString());
581 2 : EXPECT_EQ(5, String::Cast(*value)->Length());
582 2 : EXPECT_EQ(kHelloString, Utf8Value(value));
583 :
584 : value =
585 2 : DecodeTest({0xFF, 0x09, 0x53, 0x07, 'Q', 'u', 0xC3, 0xA9, 'b', 'e', 'c'});
586 1 : ASSERT_TRUE(value->IsString());
587 2 : EXPECT_EQ(6, String::Cast(*value)->Length());
588 2 : EXPECT_EQ(kQuebecString, Utf8Value(value));
589 :
590 2 : value = DecodeTest({0xFF, 0x09, 0x53, 0x04, 0xF0, 0x9F, 0x91, 0x8A});
591 1 : ASSERT_TRUE(value->IsString());
592 2 : EXPECT_EQ(2, String::Cast(*value)->Length());
593 2 : EXPECT_EQ(kEmojiString, Utf8Value(value));
594 :
595 : // And from Latin-1 (for the ones that fit).
596 2 : value = DecodeTest({0xFF, 0x0A, 0x22, 0x00});
597 1 : ASSERT_TRUE(value->IsString());
598 2 : EXPECT_EQ(0, String::Cast(*value)->Length());
599 :
600 2 : value = DecodeTest({0xFF, 0x0A, 0x22, 0x05, 'H', 'e', 'l', 'l', 'o'});
601 1 : ASSERT_TRUE(value->IsString());
602 2 : EXPECT_EQ(5, String::Cast(*value)->Length());
603 2 : EXPECT_EQ(kHelloString, Utf8Value(value));
604 :
605 2 : value = DecodeTest({0xFF, 0x0A, 0x22, 0x06, 'Q', 'u', 0xE9, 'b', 'e', 'c'});
606 1 : ASSERT_TRUE(value->IsString());
607 2 : EXPECT_EQ(6, String::Cast(*value)->Length());
608 2 : EXPECT_EQ(kQuebecString, Utf8Value(value));
609 :
610 : // And from two-byte strings (endianness dependent).
611 : #if defined(V8_TARGET_LITTLE_ENDIAN)
612 2 : value = DecodeTest({0xFF, 0x09, 0x63, 0x00});
613 1 : ASSERT_TRUE(value->IsString());
614 2 : EXPECT_EQ(0, String::Cast(*value)->Length());
615 :
616 : value = DecodeTest({0xFF, 0x09, 0x63, 0x0A, 'H', '\0', 'e', '\0', 'l', '\0',
617 2 : 'l', '\0', 'o', '\0'});
618 1 : ASSERT_TRUE(value->IsString());
619 2 : EXPECT_EQ(5, String::Cast(*value)->Length());
620 2 : EXPECT_EQ(kHelloString, Utf8Value(value));
621 :
622 : value = DecodeTest({0xFF, 0x09, 0x63, 0x0C, 'Q', '\0', 'u', '\0', 0xE9, '\0',
623 2 : 'b', '\0', 'e', '\0', 'c', '\0'});
624 1 : ASSERT_TRUE(value->IsString());
625 2 : EXPECT_EQ(6, String::Cast(*value)->Length());
626 2 : EXPECT_EQ(kQuebecString, Utf8Value(value));
627 :
628 2 : value = DecodeTest({0xFF, 0x09, 0x63, 0x04, 0x3D, 0xD8, 0x4A, 0xDC});
629 1 : ASSERT_TRUE(value->IsString());
630 2 : EXPECT_EQ(2, String::Cast(*value)->Length());
631 2 : EXPECT_EQ(kEmojiString, Utf8Value(value));
632 : #endif
633 : // TODO(jbroman): The same for big-endian systems.
634 : }
635 :
636 15444 : TEST_F(ValueSerializerTest, DecodeInvalidString) {
637 : // UTF-8 string with too few bytes available.
638 2 : InvalidDecodeTest({0xFF, 0x09, 0x53, 0x10, 'v', '8'});
639 : // One-byte string with too few bytes available.
640 2 : InvalidDecodeTest({0xFF, 0x0A, 0x22, 0x10, 'v', '8'});
641 : #if defined(V8_TARGET_LITTLE_ENDIAN)
642 : // Two-byte string with too few bytes available.
643 2 : InvalidDecodeTest({0xFF, 0x09, 0x63, 0x10, 'v', '\0', '8', '\0'});
644 : // Two-byte string with an odd byte length.
645 2 : InvalidDecodeTest({0xFF, 0x09, 0x63, 0x03, 'v', '\0', '8'});
646 : #endif
647 : // TODO(jbroman): The same for big-endian systems.
648 1 : }
649 :
650 15444 : TEST_F(ValueSerializerTest, EncodeTwoByteStringUsesPadding) {
651 : // As long as the output has a version that Blink expects to be able to read,
652 : // we must respect its alignment requirements. It requires that two-byte
653 : // characters be aligned.
654 : // We need a string whose length will take two bytes to encode, so that
655 : // a padding byte is needed to keep the characters aligned. The string
656 : // must also have a two-byte character, so that it gets the two-byte
657 : // encoding.
658 : std::string string(200, ' ');
659 : string += kEmojiString;
660 2 : const std::vector<uint8_t> data = EncodeTest(StringFromUtf8(string.c_str()));
661 : // This is a sufficient but not necessary condition. This test assumes
662 : // that the wire format version is one byte long, but is flexible to
663 : // what that value may be.
664 1 : const uint8_t expected_prefix[] = {0x00, 0x63, 0x94, 0x03};
665 2 : ASSERT_GT(data.size(), sizeof(expected_prefix) + 2);
666 2 : EXPECT_EQ(0xFF, data[0]);
667 2 : EXPECT_GE(data[1], 0x09);
668 2 : EXPECT_LE(data[1], 0x7F);
669 1 : EXPECT_TRUE(std::equal(std::begin(expected_prefix), std::end(expected_prefix),
670 0 : data.begin() + 2));
671 : }
672 :
673 15444 : TEST_F(ValueSerializerTest, RoundTripDictionaryObject) {
674 : // Empty object.
675 1 : Local<Value> value = RoundTripTest("({})");
676 2 : ASSERT_TRUE(value->IsObject());
677 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Object.prototype");
678 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 0");
679 :
680 : // String key.
681 : value = RoundTripTest("({ a: 42 })");
682 2 : ASSERT_TRUE(value->IsObject());
683 1 : ExpectScriptTrue("result.hasOwnProperty('a')");
684 1 : ExpectScriptTrue("result.a === 42");
685 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
686 :
687 : // Integer key (treated as a string, but may be encoded differently).
688 : value = RoundTripTest("({ 42: 'a' })");
689 2 : ASSERT_TRUE(value->IsObject());
690 1 : ExpectScriptTrue("result.hasOwnProperty('42')");
691 1 : ExpectScriptTrue("result[42] === 'a'");
692 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
693 :
694 : // Key order must be preserved.
695 : value = RoundTripTest("({ x: 1, y: 2, a: 3 })");
696 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).toString() === 'x,y,a'");
697 :
698 : // A harder case of enumeration order.
699 : // Indexes first, in order (but not 2^32 - 1, which is not an index), then the
700 : // remaining (string) keys, in the order they were defined.
701 : value = RoundTripTest("({ a: 2, 0xFFFFFFFF: 1, 0xFFFFFFFE: 3, 1: 0 })");
702 : ExpectScriptTrue(
703 : "Object.getOwnPropertyNames(result).toString() === "
704 1 : "'1,4294967294,a,4294967295'");
705 1 : ExpectScriptTrue("result.a === 2");
706 1 : ExpectScriptTrue("result[0xFFFFFFFF] === 1");
707 1 : ExpectScriptTrue("result[0xFFFFFFFE] === 3");
708 1 : ExpectScriptTrue("result[1] === 0");
709 :
710 : // This detects a fairly subtle case: the object itself must be in the map
711 : // before its properties are deserialized, so that references to it can be
712 : // resolved.
713 : value = RoundTripTest("var y = {}; y.self = y; y;");
714 2 : ASSERT_TRUE(value->IsObject());
715 1 : ExpectScriptTrue("result === result.self");
716 : }
717 :
718 15444 : TEST_F(ValueSerializerTest, DecodeDictionaryObject) {
719 : // Empty object.
720 : Local<Value> value =
721 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x7B, 0x00, 0x00});
722 2 : ASSERT_TRUE(value->IsObject());
723 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Object.prototype");
724 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 0");
725 :
726 : // String key.
727 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x01,
728 2 : 0x61, 0x3F, 0x01, 0x49, 0x54, 0x7B, 0x01});
729 2 : ASSERT_TRUE(value->IsObject());
730 1 : ExpectScriptTrue("result.hasOwnProperty('a')");
731 1 : ExpectScriptTrue("result.a === 42");
732 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
733 :
734 : // Integer key (treated as a string, but may be encoded differently).
735 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x49, 0x54,
736 2 : 0x3F, 0x01, 0x53, 0x01, 0x61, 0x7B, 0x01});
737 2 : ASSERT_TRUE(value->IsObject());
738 1 : ExpectScriptTrue("result.hasOwnProperty('42')");
739 1 : ExpectScriptTrue("result[42] === 'a'");
740 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
741 :
742 : // Key order must be preserved.
743 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x01,
744 : 0x78, 0x3F, 0x01, 0x49, 0x02, 0x3F, 0x01, 0x53, 0x01,
745 : 0x79, 0x3F, 0x01, 0x49, 0x04, 0x3F, 0x01, 0x53, 0x01,
746 2 : 0x61, 0x3F, 0x01, 0x49, 0x06, 0x7B, 0x03});
747 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).toString() === 'x,y,a'");
748 :
749 : // A harder case of enumeration order.
750 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x49, 0x02,
751 : 0x3F, 0x01, 0x49, 0x00, 0x3F, 0x01, 0x55, 0xFE, 0xFF,
752 : 0xFF, 0xFF, 0x0F, 0x3F, 0x01, 0x49, 0x06, 0x3F, 0x01,
753 : 0x53, 0x01, 0x61, 0x3F, 0x01, 0x49, 0x04, 0x3F, 0x01,
754 : 0x53, 0x0A, 0x34, 0x32, 0x39, 0x34, 0x39, 0x36, 0x37,
755 2 : 0x32, 0x39, 0x35, 0x3F, 0x01, 0x49, 0x02, 0x7B, 0x04});
756 : ExpectScriptTrue(
757 : "Object.getOwnPropertyNames(result).toString() === "
758 1 : "'1,4294967294,a,4294967295'");
759 1 : ExpectScriptTrue("result.a === 2");
760 1 : ExpectScriptTrue("result[0xFFFFFFFF] === 1");
761 1 : ExpectScriptTrue("result[0xFFFFFFFE] === 3");
762 1 : ExpectScriptTrue("result[1] === 0");
763 :
764 : // This detects a fairly subtle case: the object itself must be in the map
765 : // before its properties are deserialized, so that references to it can be
766 : // resolved.
767 : value =
768 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x04, 0x73,
769 2 : 0x65, 0x6C, 0x66, 0x3F, 0x01, 0x5E, 0x00, 0x7B, 0x01, 0x00});
770 2 : ASSERT_TRUE(value->IsObject());
771 1 : ExpectScriptTrue("result === result.self");
772 : }
773 :
774 15444 : TEST_F(ValueSerializerTest, InvalidDecodeObjectWithInvalidKeyType) {
775 : // Objects which would need conversion to string shouldn't be present as
776 : // object keys. The serializer would have obtained them from the own property
777 : // keys list, which should only contain names and indices.
778 2 : InvalidDecodeTest(
779 1 : {0xFF, 0x09, 0x6F, 0x61, 0x00, 0x40, 0x00, 0x00, 0x7B, 0x01});
780 1 : }
781 :
782 15444 : TEST_F(ValueSerializerTest, RoundTripOnlyOwnEnumerableStringKeys) {
783 : // Only "own" properties should be serialized, not ones on the prototype.
784 1 : Local<Value> value = RoundTripTest("var x = {}; x.__proto__ = {a: 4}; x;");
785 1 : ExpectScriptTrue("!('a' in result)");
786 :
787 : // Only enumerable properties should be serialized.
788 : value = RoundTripTest(
789 : "var x = {};"
790 : "Object.defineProperty(x, 'a', {value: 1, enumerable: false});"
791 : "x;");
792 1 : ExpectScriptTrue("!('a' in result)");
793 :
794 : // Symbol keys should not be serialized.
795 : value = RoundTripTest("({ [Symbol()]: 4 })");
796 1 : ExpectScriptTrue("Object.getOwnPropertySymbols(result).length === 0");
797 1 : }
798 :
799 15444 : TEST_F(ValueSerializerTest, RoundTripTrickyGetters) {
800 : // Keys are enumerated before any setters are called, but if there is no own
801 : // property when the value is to be read, then it should not be serialized.
802 : Local<Value> value =
803 1 : RoundTripTest("({ get a() { delete this.b; return 1; }, b: 2 })");
804 1 : ExpectScriptTrue("!('b' in result)");
805 :
806 : // Keys added after the property enumeration should not be serialized.
807 : value = RoundTripTest("({ get a() { this.b = 3; }})");
808 1 : ExpectScriptTrue("!('b' in result)");
809 :
810 : // But if you remove a key and add it back, that's fine. But it will appear in
811 : // the original place in enumeration order.
812 : value =
813 : RoundTripTest("({ get a() { delete this.b; this.b = 4; }, b: 2, c: 3 })");
814 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).toString() === 'a,b,c'");
815 1 : ExpectScriptTrue("result.b === 4");
816 :
817 : // Similarly, it only matters if a property was enumerable when the
818 : // enumeration happened.
819 : value = RoundTripTest(
820 : "({ get a() {"
821 : " Object.defineProperty(this, 'b', {value: 2, enumerable: false});"
822 : "}, b: 1})");
823 1 : ExpectScriptTrue("result.b === 2");
824 :
825 : value = RoundTripTest(
826 : "var x = {"
827 : " get a() {"
828 : " Object.defineProperty(this, 'b', {value: 2, enumerable: true});"
829 : " }"
830 : "};"
831 : "Object.defineProperty(x, 'b',"
832 : " {value: 1, enumerable: false, configurable: true});"
833 : "x;");
834 1 : ExpectScriptTrue("!('b' in result)");
835 :
836 : // The property also should not be read if it can only be found on the
837 : // prototype chain (but not as an own property) after enumeration.
838 : value = RoundTripTest(
839 : "var x = { get a() { delete this.b; }, b: 1 };"
840 : "x.__proto__ = { b: 0 };"
841 : "x;");
842 1 : ExpectScriptTrue("!('b' in result)");
843 :
844 : // If an exception is thrown by script, encoding must fail and the exception
845 : // must be thrown.
846 : Local<Message> message =
847 : InvalidEncodeTest("({ get a() { throw new Error('sentinel'); } })");
848 2 : ASSERT_FALSE(message.IsEmpty());
849 4 : EXPECT_NE(std::string::npos, Utf8Value(message->Get()).find("sentinel"));
850 : }
851 :
852 15444 : TEST_F(ValueSerializerTest, RoundTripDictionaryObjectForTransitions) {
853 : // A case which should run on the fast path, and should reach all of the
854 : // different cases:
855 : // 1. no known transition (first time creating this kind of object)
856 : // 2. expected transitions match to end
857 : // 3. transition partially matches, but falls back due to new property 'w'
858 : // 4. transition to 'z' is now a full transition (needs to be looked up)
859 : // 5. same for 'w'
860 : // 6. new property after complex transition succeeded
861 : // 7. new property after complex transition failed (due to new property)
862 1 : RoundTripJSON(
863 : "[{\"x\":1,\"y\":2,\"z\":3}"
864 : ",{\"x\":4,\"y\":5,\"z\":6}"
865 : ",{\"x\":5,\"y\":6,\"w\":7}"
866 : ",{\"x\":6,\"y\":7,\"z\":8}"
867 : ",{\"x\":0,\"y\":0,\"w\":0}"
868 : ",{\"x\":3,\"y\":1,\"w\":4,\"z\":1}"
869 1 : ",{\"x\":5,\"y\":9,\"k\":2,\"z\":6}]");
870 : // A simpler case that uses two-byte strings.
871 : RoundTripJSON(
872 : "[{\"\xF0\x9F\x91\x8A\":1,\"\xF0\x9F\x91\x8B\":2}"
873 : ",{\"\xF0\x9F\x91\x8A\":3,\"\xF0\x9F\x91\x8C\":4}"
874 1 : ",{\"\xF0\x9F\x91\x8A\":5,\"\xF0\x9F\x91\x9B\":6}]");
875 1 : }
876 :
877 15444 : TEST_F(ValueSerializerTest, DecodeDictionaryObjectVersion0) {
878 : // Empty object.
879 2 : Local<Value> value = DecodeTestForVersion0({0x7B, 0x00});
880 2 : ASSERT_TRUE(value->IsObject());
881 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Object.prototype");
882 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 0");
883 :
884 : // String key.
885 : value =
886 2 : DecodeTestForVersion0({0x53, 0x01, 0x61, 0x49, 0x54, 0x7B, 0x01, 0x00});
887 2 : ASSERT_TRUE(value->IsObject());
888 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Object.prototype");
889 1 : ExpectScriptTrue("result.hasOwnProperty('a')");
890 1 : ExpectScriptTrue("result.a === 42");
891 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
892 :
893 : // Integer key (treated as a string, but may be encoded differently).
894 : value =
895 2 : DecodeTestForVersion0({0x49, 0x54, 0x53, 0x01, 0x61, 0x7B, 0x01, 0x00});
896 2 : ASSERT_TRUE(value->IsObject());
897 1 : ExpectScriptTrue("result.hasOwnProperty('42')");
898 1 : ExpectScriptTrue("result[42] === 'a'");
899 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).length === 1");
900 :
901 : // Key order must be preserved.
902 : value = DecodeTestForVersion0({0x53, 0x01, 0x78, 0x49, 0x02, 0x53, 0x01, 0x79,
903 : 0x49, 0x04, 0x53, 0x01, 0x61, 0x49, 0x06, 0x7B,
904 2 : 0x03, 0x00});
905 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).toString() === 'x,y,a'");
906 :
907 : // A property and an element.
908 : value = DecodeTestForVersion0(
909 2 : {0x49, 0x54, 0x53, 0x01, 0x61, 0x53, 0x01, 0x61, 0x49, 0x54, 0x7B, 0x02});
910 1 : ExpectScriptTrue("Object.getOwnPropertyNames(result).toString() === '42,a'");
911 1 : ExpectScriptTrue("result[42] === 'a'");
912 1 : ExpectScriptTrue("result.a === 42");
913 : }
914 :
915 15444 : TEST_F(ValueSerializerTest, RoundTripArray) {
916 : // A simple array of integers.
917 1 : Local<Value> value = RoundTripTest("[1, 2, 3, 4, 5]");
918 2 : ASSERT_TRUE(value->IsArray());
919 2 : EXPECT_EQ(5u, Array::Cast(*value)->Length());
920 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Array.prototype");
921 1 : ExpectScriptTrue("result.toString() === '1,2,3,4,5'");
922 :
923 : // A long (sparse) array.
924 : value = RoundTripTest("var x = new Array(1000); x[500] = 42; x;");
925 2 : ASSERT_TRUE(value->IsArray());
926 2 : EXPECT_EQ(1000u, Array::Cast(*value)->Length());
927 1 : ExpectScriptTrue("result[500] === 42");
928 :
929 : // Duplicate reference.
930 : value = RoundTripTest("var y = {}; [y, y];");
931 2 : ASSERT_TRUE(value->IsArray());
932 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
933 1 : ExpectScriptTrue("result[0] === result[1]");
934 :
935 : // Duplicate reference in a sparse array.
936 : value = RoundTripTest("var x = new Array(1000); x[1] = x[500] = {}; x;");
937 2 : ASSERT_TRUE(value->IsArray());
938 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
939 1 : ExpectScriptTrue("typeof result[1] === 'object'");
940 1 : ExpectScriptTrue("result[1] === result[500]");
941 :
942 : // Self reference.
943 : value = RoundTripTest("var y = []; y[0] = y; y;");
944 2 : ASSERT_TRUE(value->IsArray());
945 2 : ASSERT_EQ(1u, Array::Cast(*value)->Length());
946 1 : ExpectScriptTrue("result[0] === result");
947 :
948 : // Self reference in a sparse array.
949 : value = RoundTripTest("var y = new Array(1000); y[519] = y; y;");
950 2 : ASSERT_TRUE(value->IsArray());
951 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
952 1 : ExpectScriptTrue("result[519] === result");
953 :
954 : // Array with additional properties.
955 : value = RoundTripTest("var y = [1, 2]; y.foo = 'bar'; y;");
956 2 : ASSERT_TRUE(value->IsArray());
957 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
958 1 : ExpectScriptTrue("result.toString() === '1,2'");
959 1 : ExpectScriptTrue("result.foo === 'bar'");
960 :
961 : // Sparse array with additional properties.
962 : value = RoundTripTest("var y = new Array(1000); y.foo = 'bar'; y;");
963 2 : ASSERT_TRUE(value->IsArray());
964 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
965 1 : ExpectScriptTrue("result.toString() === ','.repeat(999)");
966 1 : ExpectScriptTrue("result.foo === 'bar'");
967 :
968 : // The distinction between holes and undefined elements must be maintained.
969 : value = RoundTripTest("[,undefined]");
970 2 : ASSERT_TRUE(value->IsArray());
971 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
972 1 : ExpectScriptTrue("typeof result[0] === 'undefined'");
973 1 : ExpectScriptTrue("typeof result[1] === 'undefined'");
974 1 : ExpectScriptTrue("!result.hasOwnProperty(0)");
975 1 : ExpectScriptTrue("result.hasOwnProperty(1)");
976 : }
977 :
978 15444 : TEST_F(ValueSerializerTest, DecodeArray) {
979 : // A simple array of integers.
980 : Local<Value> value =
981 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x41, 0x05, 0x3F, 0x01, 0x49, 0x02,
982 : 0x3F, 0x01, 0x49, 0x04, 0x3F, 0x01, 0x49, 0x06, 0x3F, 0x01,
983 2 : 0x49, 0x08, 0x3F, 0x01, 0x49, 0x0A, 0x24, 0x00, 0x05, 0x00});
984 2 : ASSERT_TRUE(value->IsArray());
985 2 : EXPECT_EQ(5u, Array::Cast(*value)->Length());
986 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Array.prototype");
987 1 : ExpectScriptTrue("result.toString() === '1,2,3,4,5'");
988 :
989 : // A long (sparse) array.
990 : value =
991 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x61, 0xE8, 0x07, 0x3F, 0x01, 0x49,
992 2 : 0xE8, 0x07, 0x3F, 0x01, 0x49, 0x54, 0x40, 0x01, 0xE8, 0x07});
993 2 : ASSERT_TRUE(value->IsArray());
994 2 : EXPECT_EQ(1000u, Array::Cast(*value)->Length());
995 1 : ExpectScriptTrue("result[500] === 42");
996 :
997 : // Duplicate reference.
998 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x41, 0x02, 0x3F, 0x01, 0x6F,
999 2 : 0x7B, 0x00, 0x3F, 0x02, 0x5E, 0x01, 0x24, 0x00, 0x02});
1000 2 : ASSERT_TRUE(value->IsArray());
1001 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1002 1 : ExpectScriptTrue("result[0] === result[1]");
1003 :
1004 : // Duplicate reference in a sparse array.
1005 : value =
1006 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x61, 0xE8, 0x07, 0x3F, 0x01, 0x49,
1007 : 0x02, 0x3F, 0x01, 0x6F, 0x7B, 0x00, 0x3F, 0x02, 0x49, 0xE8,
1008 2 : 0x07, 0x3F, 0x02, 0x5E, 0x01, 0x40, 0x02, 0xE8, 0x07, 0x00});
1009 2 : ASSERT_TRUE(value->IsArray());
1010 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1011 1 : ExpectScriptTrue("typeof result[1] === 'object'");
1012 1 : ExpectScriptTrue("result[1] === result[500]");
1013 :
1014 : // Self reference.
1015 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x41, 0x01, 0x3F, 0x01, 0x5E,
1016 2 : 0x00, 0x24, 0x00, 0x01, 0x00});
1017 2 : ASSERT_TRUE(value->IsArray());
1018 2 : ASSERT_EQ(1u, Array::Cast(*value)->Length());
1019 1 : ExpectScriptTrue("result[0] === result");
1020 :
1021 : // Self reference in a sparse array.
1022 : value =
1023 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x61, 0xE8, 0x07, 0x3F, 0x01, 0x49,
1024 2 : 0x8E, 0x08, 0x3F, 0x01, 0x5E, 0x00, 0x40, 0x01, 0xE8, 0x07});
1025 2 : ASSERT_TRUE(value->IsArray());
1026 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1027 1 : ExpectScriptTrue("result[519] === result");
1028 :
1029 : // Array with additional properties.
1030 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x41, 0x02, 0x3F, 0x01,
1031 : 0x49, 0x02, 0x3F, 0x01, 0x49, 0x04, 0x3F, 0x01,
1032 : 0x53, 0x03, 0x66, 0x6F, 0x6F, 0x3F, 0x01, 0x53,
1033 2 : 0x03, 0x62, 0x61, 0x72, 0x24, 0x01, 0x02, 0x00});
1034 2 : ASSERT_TRUE(value->IsArray());
1035 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1036 1 : ExpectScriptTrue("result.toString() === '1,2'");
1037 1 : ExpectScriptTrue("result.foo === 'bar'");
1038 :
1039 : // Sparse array with additional properties.
1040 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x61, 0xE8, 0x07, 0x3F, 0x01,
1041 : 0x53, 0x03, 0x66, 0x6F, 0x6F, 0x3F, 0x01, 0x53, 0x03,
1042 2 : 0x62, 0x61, 0x72, 0x40, 0x01, 0xE8, 0x07, 0x00});
1043 2 : ASSERT_TRUE(value->IsArray());
1044 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1045 1 : ExpectScriptTrue("result.toString() === ','.repeat(999)");
1046 1 : ExpectScriptTrue("result.foo === 'bar'");
1047 :
1048 : // The distinction between holes and undefined elements must be maintained.
1049 : // Note that since the previous output from Chrome fails this test, an
1050 : // encoding using the sparse format was constructed instead.
1051 : value =
1052 2 : DecodeTest({0xFF, 0x09, 0x61, 0x02, 0x49, 0x02, 0x5F, 0x40, 0x01, 0x02});
1053 2 : ASSERT_TRUE(value->IsArray());
1054 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1055 1 : ExpectScriptTrue("typeof result[0] === 'undefined'");
1056 1 : ExpectScriptTrue("typeof result[1] === 'undefined'");
1057 1 : ExpectScriptTrue("!result.hasOwnProperty(0)");
1058 1 : ExpectScriptTrue("result.hasOwnProperty(1)");
1059 : }
1060 :
1061 15444 : TEST_F(ValueSerializerTest, DecodeInvalidOverLargeArray) {
1062 : // So large it couldn't exist in the V8 heap, and its size couldn't fit in a
1063 : // SMI on 32-bit systems (2^30).
1064 2 : InvalidDecodeTest({0xFF, 0x09, 0x41, 0x80, 0x80, 0x80, 0x80, 0x04});
1065 : // Not so large, but there isn't enough data left in the buffer.
1066 2 : InvalidDecodeTest({0xFF, 0x09, 0x41, 0x01});
1067 1 : }
1068 :
1069 15444 : TEST_F(ValueSerializerTest, RoundTripArrayWithNonEnumerableElement) {
1070 : // Even though this array looks like [1,5,3], the 5 should be missing from the
1071 : // perspective of structured clone, which only clones properties that were
1072 : // enumerable.
1073 : Local<Value> value = RoundTripTest(
1074 : "var x = [1,2,3];"
1075 : "Object.defineProperty(x, '1', {enumerable:false, value:5});"
1076 1 : "x;");
1077 2 : ASSERT_TRUE(value->IsArray());
1078 2 : ASSERT_EQ(3u, Array::Cast(*value)->Length());
1079 1 : ExpectScriptTrue("!result.hasOwnProperty('1')");
1080 : }
1081 :
1082 15444 : TEST_F(ValueSerializerTest, RoundTripArrayWithTrickyGetters) {
1083 : // If an element is deleted before it is serialized, then it's deleted.
1084 : Local<Value> value =
1085 1 : RoundTripTest("var x = [{ get a() { delete x[1]; }}, 42]; x;");
1086 2 : ASSERT_TRUE(value->IsArray());
1087 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1088 1 : ExpectScriptTrue("typeof result[1] === 'undefined'");
1089 1 : ExpectScriptTrue("!result.hasOwnProperty(1)");
1090 :
1091 : // Same for sparse arrays.
1092 : value = RoundTripTest(
1093 : "var x = [{ get a() { delete x[1]; }}, 42];"
1094 : "x.length = 1000;"
1095 : "x;");
1096 2 : ASSERT_TRUE(value->IsArray());
1097 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1098 1 : ExpectScriptTrue("typeof result[1] === 'undefined'");
1099 1 : ExpectScriptTrue("!result.hasOwnProperty(1)");
1100 :
1101 : // If the length is changed, then the resulting array still has the original
1102 : // length, but elements that were not yet serialized are gone.
1103 : value = RoundTripTest("var x = [1, { get a() { x.length = 0; }}, 3, 4]; x;");
1104 2 : ASSERT_TRUE(value->IsArray());
1105 2 : ASSERT_EQ(4u, Array::Cast(*value)->Length());
1106 1 : ExpectScriptTrue("result[0] === 1");
1107 1 : ExpectScriptTrue("!result.hasOwnProperty(2)");
1108 :
1109 : // The same is true if the length is shortened, but there are still items
1110 : // remaining.
1111 : value = RoundTripTest("var x = [1, { get a() { x.length = 3; }}, 3, 4]; x;");
1112 2 : ASSERT_TRUE(value->IsArray());
1113 2 : ASSERT_EQ(4u, Array::Cast(*value)->Length());
1114 1 : ExpectScriptTrue("result[2] === 3");
1115 1 : ExpectScriptTrue("!result.hasOwnProperty(3)");
1116 :
1117 : // Same for sparse arrays.
1118 : value = RoundTripTest(
1119 : "var x = [1, { get a() { x.length = 0; }}, 3, 4];"
1120 : "x.length = 1000;"
1121 : "x;");
1122 2 : ASSERT_TRUE(value->IsArray());
1123 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1124 1 : ExpectScriptTrue("result[0] === 1");
1125 1 : ExpectScriptTrue("!result.hasOwnProperty(2)");
1126 :
1127 : value = RoundTripTest(
1128 : "var x = [1, { get a() { x.length = 3; }}, 3, 4];"
1129 : "x.length = 1000;"
1130 : "x;");
1131 2 : ASSERT_TRUE(value->IsArray());
1132 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1133 1 : ExpectScriptTrue("result[2] === 3");
1134 1 : ExpectScriptTrue("!result.hasOwnProperty(3)");
1135 :
1136 : // If a getter makes a property non-enumerable, it should still be enumerated
1137 : // as enumeration happens once before getters are invoked.
1138 : value = RoundTripTest(
1139 : "var x = [{ get a() {"
1140 : " Object.defineProperty(x, '1', { value: 3, enumerable: false });"
1141 : "}}, 2];"
1142 : "x;");
1143 2 : ASSERT_TRUE(value->IsArray());
1144 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1145 1 : ExpectScriptTrue("result[1] === 3");
1146 :
1147 : // Same for sparse arrays.
1148 : value = RoundTripTest(
1149 : "var x = [{ get a() {"
1150 : " Object.defineProperty(x, '1', { value: 3, enumerable: false });"
1151 : "}}, 2];"
1152 : "x.length = 1000;"
1153 : "x;");
1154 2 : ASSERT_TRUE(value->IsArray());
1155 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1156 1 : ExpectScriptTrue("result[1] === 3");
1157 :
1158 : // Getters on the array itself must also run.
1159 : value = RoundTripTest(
1160 : "var x = [1, 2, 3];"
1161 : "Object.defineProperty(x, '1', { enumerable: true, get: () => 4 });"
1162 : "x;");
1163 2 : ASSERT_TRUE(value->IsArray());
1164 2 : ASSERT_EQ(3u, Array::Cast(*value)->Length());
1165 1 : ExpectScriptTrue("result[1] === 4");
1166 :
1167 : // Same for sparse arrays.
1168 : value = RoundTripTest(
1169 : "var x = [1, 2, 3];"
1170 : "Object.defineProperty(x, '1', { enumerable: true, get: () => 4 });"
1171 : "x.length = 1000;"
1172 : "x;");
1173 2 : ASSERT_TRUE(value->IsArray());
1174 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1175 1 : ExpectScriptTrue("result[1] === 4");
1176 :
1177 : // Even with a getter that deletes things, we don't read from the prototype.
1178 : value = RoundTripTest(
1179 : "var x = [{ get a() { delete x[1]; } }, 2];"
1180 : "x.__proto__ = Object.create(Array.prototype, { 1: { value: 6 } });"
1181 : "x;");
1182 2 : ASSERT_TRUE(value->IsArray());
1183 2 : ASSERT_EQ(2u, Array::Cast(*value)->Length());
1184 1 : ExpectScriptTrue("!(1 in result)");
1185 :
1186 : // Same for sparse arrays.
1187 : value = RoundTripTest(
1188 : "var x = [{ get a() { delete x[1]; } }, 2];"
1189 : "x.__proto__ = Object.create(Array.prototype, { 1: { value: 6 } });"
1190 : "x.length = 1000;"
1191 : "x;");
1192 2 : ASSERT_TRUE(value->IsArray());
1193 2 : ASSERT_EQ(1000u, Array::Cast(*value)->Length());
1194 1 : ExpectScriptTrue("!(1 in result)");
1195 : }
1196 :
1197 15444 : TEST_F(ValueSerializerTest, DecodeSparseArrayVersion0) {
1198 : // Empty (sparse) array.
1199 2 : Local<Value> value = DecodeTestForVersion0({0x40, 0x00, 0x00, 0x00});
1200 2 : ASSERT_TRUE(value->IsArray());
1201 2 : ASSERT_EQ(0u, Array::Cast(*value)->Length());
1202 :
1203 : // Sparse array with a mixture of elements and properties.
1204 : value = DecodeTestForVersion0({0x55, 0x00, 0x53, 0x01, 'a', 0x55, 0x02, 0x55,
1205 : 0x05, 0x53, 0x03, 'f', 'o', 'o', 0x53, 0x03,
1206 : 'b', 'a', 'r', 0x53, 0x03, 'b', 'a', 'z',
1207 2 : 0x49, 0x0B, 0x40, 0x04, 0x03, 0x00});
1208 2 : ASSERT_TRUE(value->IsArray());
1209 2 : EXPECT_EQ(3u, Array::Cast(*value)->Length());
1210 1 : ExpectScriptTrue("result.toString() === 'a,,5'");
1211 1 : ExpectScriptTrue("!(1 in result)");
1212 1 : ExpectScriptTrue("result.foo === 'bar'");
1213 1 : ExpectScriptTrue("result.baz === -6");
1214 :
1215 : // Sparse array in a sparse array (sanity check of nesting).
1216 : value = DecodeTestForVersion0(
1217 2 : {0x55, 0x01, 0x55, 0x01, 0x54, 0x40, 0x01, 0x02, 0x40, 0x01, 0x02, 0x00});
1218 2 : ASSERT_TRUE(value->IsArray());
1219 2 : EXPECT_EQ(2u, Array::Cast(*value)->Length());
1220 1 : ExpectScriptTrue("!(0 in result)");
1221 1 : ExpectScriptTrue("result[1] instanceof Array");
1222 1 : ExpectScriptTrue("!(0 in result[1])");
1223 1 : ExpectScriptTrue("result[1][1] === true");
1224 : }
1225 :
1226 15444 : TEST_F(ValueSerializerTest, RoundTripDenseArrayContainingUndefined) {
1227 : // In previous serialization versions, this would be interpreted as an absent
1228 : // property.
1229 1 : Local<Value> value = RoundTripTest("[undefined]");
1230 2 : ASSERT_TRUE(value->IsArray());
1231 2 : EXPECT_EQ(1u, Array::Cast(*value)->Length());
1232 1 : ExpectScriptTrue("result.hasOwnProperty(0)");
1233 1 : ExpectScriptTrue("result[0] === undefined");
1234 : }
1235 :
1236 15444 : TEST_F(ValueSerializerTest, DecodeDenseArrayContainingUndefined) {
1237 : // In previous versions, "undefined" in a dense array signified absence of the
1238 : // element (for compatibility). In new versions, it has a separate encoding.
1239 : Local<Value> value =
1240 2 : DecodeTest({0xFF, 0x09, 0x41, 0x01, 0x5F, 0x24, 0x00, 0x01});
1241 1 : ExpectScriptTrue("!(0 in result)");
1242 :
1243 2 : value = DecodeTest({0xFF, 0x0B, 0x41, 0x01, 0x5F, 0x24, 0x00, 0x01});
1244 1 : ExpectScriptTrue("0 in result");
1245 1 : ExpectScriptTrue("result[0] === undefined");
1246 :
1247 2 : value = DecodeTest({0xFF, 0x0B, 0x41, 0x01, 0x2D, 0x24, 0x00, 0x01});
1248 1 : ExpectScriptTrue("!(0 in result)");
1249 1 : }
1250 :
1251 15444 : TEST_F(ValueSerializerTest, RoundTripDate) {
1252 1 : Local<Value> value = RoundTripTest("new Date(1e6)");
1253 2 : ASSERT_TRUE(value->IsDate());
1254 2 : EXPECT_EQ(1e6, Date::Cast(*value)->ValueOf());
1255 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Date.prototype");
1256 :
1257 : value = RoundTripTest("new Date(Date.UTC(1867, 6, 1))");
1258 2 : ASSERT_TRUE(value->IsDate());
1259 1 : ExpectScriptTrue("result.toISOString() === '1867-07-01T00:00:00.000Z'");
1260 :
1261 : value = RoundTripTest("new Date(NaN)");
1262 2 : ASSERT_TRUE(value->IsDate());
1263 2 : EXPECT_TRUE(std::isnan(Date::Cast(*value)->ValueOf()));
1264 :
1265 : value = RoundTripTest("({ a: new Date(), get b() { return this.a; } })");
1266 1 : ExpectScriptTrue("result.a instanceof Date");
1267 1 : ExpectScriptTrue("result.a === result.b");
1268 : }
1269 :
1270 15444 : TEST_F(ValueSerializerTest, DecodeDate) {
1271 : Local<Value> value;
1272 : #if defined(V8_TARGET_LITTLE_ENDIAN)
1273 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00,
1274 2 : 0x80, 0x84, 0x2E, 0x41, 0x00});
1275 2 : ASSERT_TRUE(value->IsDate());
1276 2 : EXPECT_EQ(1e6, Date::Cast(*value)->ValueOf());
1277 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Date.prototype");
1278 :
1279 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0x00, 0x00, 0x20, 0x45,
1280 2 : 0x27, 0x89, 0x87, 0xC2, 0x00});
1281 2 : ASSERT_TRUE(value->IsDate());
1282 1 : ExpectScriptTrue("result.toISOString() === '1867-07-01T00:00:00.000Z'");
1283 :
1284 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00,
1285 2 : 0x00, 0x00, 0xF8, 0x7F, 0x00});
1286 2 : ASSERT_TRUE(value->IsDate());
1287 2 : EXPECT_TRUE(std::isnan(Date::Cast(*value)->ValueOf()));
1288 : #else
1289 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0x41, 0x2E, 0x84, 0x80,
1290 : 0x00, 0x00, 0x00, 0x00, 0x00});
1291 : ASSERT_TRUE(value->IsDate());
1292 : EXPECT_EQ(1e6, Date::Cast(*value)->ValueOf());
1293 : ExpectScriptTrue("Object.getPrototypeOf(result) === Date.prototype");
1294 :
1295 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0xC2, 0x87, 0x89, 0x27,
1296 : 0x45, 0x20, 0x00, 0x00, 0x00});
1297 : ASSERT_TRUE(value->IsDate());
1298 : ExpectScriptTrue("result.toISOString() === '1867-07-01T00:00:00.000Z'");
1299 :
1300 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x44, 0x7F, 0xF8, 0x00, 0x00,
1301 : 0x00, 0x00, 0x00, 0x00, 0x00});
1302 : ASSERT_TRUE(value->IsDate());
1303 : EXPECT_TRUE(std::isnan(Date::Cast(*value)->ValueOf()));
1304 : #endif
1305 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53,
1306 : 0x01, 0x61, 0x3F, 0x01, 0x44, 0x00, 0x20, 0x39,
1307 : 0x50, 0x37, 0x6A, 0x75, 0x42, 0x3F, 0x02, 0x53,
1308 2 : 0x01, 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02});
1309 1 : ExpectScriptTrue("result.a instanceof Date");
1310 1 : ExpectScriptTrue("result.a === result.b");
1311 : }
1312 :
1313 15444 : TEST_F(ValueSerializerTest, RoundTripValueObjects) {
1314 1 : Local<Value> value = RoundTripTest("new Boolean(true)");
1315 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Boolean.prototype");
1316 1 : ExpectScriptTrue("result.valueOf() === true");
1317 :
1318 : value = RoundTripTest("new Boolean(false)");
1319 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Boolean.prototype");
1320 1 : ExpectScriptTrue("result.valueOf() === false");
1321 :
1322 : value =
1323 : RoundTripTest("({ a: new Boolean(true), get b() { return this.a; }})");
1324 1 : ExpectScriptTrue("result.a instanceof Boolean");
1325 1 : ExpectScriptTrue("result.a === result.b");
1326 :
1327 : value = RoundTripTest("new Number(-42)");
1328 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1329 1 : ExpectScriptTrue("result.valueOf() === -42");
1330 :
1331 : value = RoundTripTest("new Number(NaN)");
1332 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1333 1 : ExpectScriptTrue("Number.isNaN(result.valueOf())");
1334 :
1335 : value = RoundTripTest("({ a: new Number(6), get b() { return this.a; }})");
1336 1 : ExpectScriptTrue("result.a instanceof Number");
1337 1 : ExpectScriptTrue("result.a === result.b");
1338 :
1339 : value = RoundTripTest("new String('Qu\\xe9bec')");
1340 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === String.prototype");
1341 1 : ExpectScriptTrue("result.valueOf() === 'Qu\\xe9bec'");
1342 1 : ExpectScriptTrue("result.length === 6");
1343 :
1344 : value = RoundTripTest("new String('\\ud83d\\udc4a')");
1345 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === String.prototype");
1346 1 : ExpectScriptTrue("result.valueOf() === '\\ud83d\\udc4a'");
1347 1 : ExpectScriptTrue("result.length === 2");
1348 :
1349 : value = RoundTripTest("({ a: new String(), get b() { return this.a; }})");
1350 1 : ExpectScriptTrue("result.a instanceof String");
1351 1 : ExpectScriptTrue("result.a === result.b");
1352 1 : }
1353 :
1354 15444 : TEST_F(ValueSerializerTest, RejectsOtherValueObjects) {
1355 : // This is a roundabout way of getting an instance of Symbol.
1356 1 : InvalidEncodeTest("Object.valueOf.apply(Symbol())");
1357 1 : }
1358 :
1359 15444 : TEST_F(ValueSerializerTest, DecodeValueObjects) {
1360 2 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x79, 0x00});
1361 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Boolean.prototype");
1362 1 : ExpectScriptTrue("result.valueOf() === true");
1363 :
1364 2 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x78, 0x00});
1365 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Boolean.prototype");
1366 1 : ExpectScriptTrue("result.valueOf() === false");
1367 :
1368 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53,
1369 : 0x01, 0x61, 0x3F, 0x01, 0x79, 0x3F, 0x02, 0x53,
1370 2 : 0x01, 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02});
1371 1 : ExpectScriptTrue("result.a instanceof Boolean");
1372 1 : ExpectScriptTrue("result.a === result.b");
1373 :
1374 : #if defined(V8_TARGET_LITTLE_ENDIAN)
1375 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00,
1376 2 : 0x00, 0x00, 0x45, 0xC0, 0x00});
1377 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1378 1 : ExpectScriptTrue("result.valueOf() === -42");
1379 :
1380 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00,
1381 2 : 0x00, 0x00, 0xF8, 0x7F, 0x00});
1382 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1383 1 : ExpectScriptTrue("Number.isNaN(result.valueOf())");
1384 : #else
1385 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6E, 0xC0, 0x45, 0x00, 0x00,
1386 : 0x00, 0x00, 0x00, 0x00, 0x00});
1387 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1388 : ExpectScriptTrue("result.valueOf() === -42");
1389 :
1390 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6E, 0x7F, 0xF8, 0x00, 0x00,
1391 : 0x00, 0x00, 0x00, 0x00, 0x00});
1392 : ExpectScriptTrue("Object.getPrototypeOf(result) === Number.prototype");
1393 : ExpectScriptTrue("Number.isNaN(result.valueOf())");
1394 : #endif
1395 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53,
1396 : 0x01, 0x61, 0x3F, 0x01, 0x6E, 0x00, 0x00, 0x00,
1397 : 0x00, 0x00, 0x00, 0x18, 0x40, 0x3F, 0x02, 0x53,
1398 2 : 0x01, 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02});
1399 1 : ExpectScriptTrue("result.a instanceof Number");
1400 1 : ExpectScriptTrue("result.a === result.b");
1401 :
1402 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x73, 0x07, 0x51, 0x75, 0xC3,
1403 2 : 0xA9, 0x62, 0x65, 0x63, 0x00});
1404 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === String.prototype");
1405 1 : ExpectScriptTrue("result.valueOf() === 'Qu\\xe9bec'");
1406 1 : ExpectScriptTrue("result.length === 6");
1407 :
1408 : value =
1409 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x73, 0x04, 0xF0, 0x9F, 0x91, 0x8A});
1410 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === String.prototype");
1411 1 : ExpectScriptTrue("result.valueOf() === '\\ud83d\\udc4a'");
1412 1 : ExpectScriptTrue("result.length === 2");
1413 :
1414 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x01,
1415 : 0x61, 0x3F, 0x01, 0x73, 0x00, 0x3F, 0x02, 0x53, 0x01,
1416 2 : 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02, 0x00});
1417 1 : ExpectScriptTrue("result.a instanceof String");
1418 1 : ExpectScriptTrue("result.a === result.b");
1419 :
1420 : // String object containing a Latin-1 string.
1421 : value =
1422 2 : DecodeTest({0xFF, 0x0C, 0x73, 0x22, 0x06, 'Q', 'u', 0xE9, 'b', 'e', 'c'});
1423 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === String.prototype");
1424 1 : ExpectScriptTrue("result.valueOf() === 'Qu\\xe9bec'");
1425 1 : ExpectScriptTrue("result.length === 6");
1426 1 : }
1427 :
1428 15444 : TEST_F(ValueSerializerTest, RoundTripRegExp) {
1429 1 : Local<Value> value = RoundTripTest("/foo/g");
1430 2 : ASSERT_TRUE(value->IsRegExp());
1431 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === RegExp.prototype");
1432 1 : ExpectScriptTrue("result.toString() === '/foo/g'");
1433 :
1434 : value = RoundTripTest("new RegExp('Qu\\xe9bec', 'i')");
1435 2 : ASSERT_TRUE(value->IsRegExp());
1436 1 : ExpectScriptTrue("result.toString() === '/Qu\\xe9bec/i'");
1437 :
1438 : value = RoundTripTest("new RegExp('\\ud83d\\udc4a', 'ug')");
1439 2 : ASSERT_TRUE(value->IsRegExp());
1440 1 : ExpectScriptTrue("result.toString() === '/\\ud83d\\udc4a/gu'");
1441 :
1442 : value = RoundTripTest("({ a: /foo/gi, get b() { return this.a; }})");
1443 1 : ExpectScriptTrue("result.a instanceof RegExp");
1444 1 : ExpectScriptTrue("result.a === result.b");
1445 : }
1446 :
1447 15444 : TEST_F(ValueSerializerTest, DecodeRegExp) {
1448 : Local<Value> value =
1449 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x52, 0x03, 0x66, 0x6F, 0x6F, 0x01});
1450 2 : ASSERT_TRUE(value->IsRegExp());
1451 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === RegExp.prototype");
1452 1 : ExpectScriptTrue("result.toString() === '/foo/g'");
1453 :
1454 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x52, 0x07, 0x51, 0x75, 0xC3,
1455 2 : 0xA9, 0x62, 0x65, 0x63, 0x02});
1456 2 : ASSERT_TRUE(value->IsRegExp());
1457 1 : ExpectScriptTrue("result.toString() === '/Qu\\xe9bec/i'");
1458 :
1459 : value = DecodeTest(
1460 2 : {0xFF, 0x09, 0x3F, 0x00, 0x52, 0x04, 0xF0, 0x9F, 0x91, 0x8A, 0x11, 0x00});
1461 2 : ASSERT_TRUE(value->IsRegExp());
1462 1 : ExpectScriptTrue("result.toString() === '/\\ud83d\\udc4a/gu'");
1463 :
1464 : value =
1465 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x01, 0x61,
1466 : 0x3F, 0x01, 0x52, 0x03, 0x66, 0x6F, 0x6F, 0x03, 0x3F, 0x02,
1467 2 : 0x53, 0x01, 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02, 0x00});
1468 1 : ExpectScriptTrue("result.a instanceof RegExp");
1469 1 : ExpectScriptTrue("result.a === result.b");
1470 :
1471 : // RegExp containing a Latin-1 string.
1472 : value = DecodeTest(
1473 2 : {0xFF, 0x0C, 0x52, 0x22, 0x06, 'Q', 'u', 0xE9, 'b', 'e', 'c', 0x02});
1474 2 : ASSERT_TRUE(value->IsRegExp());
1475 1 : ExpectScriptTrue("result.toString() === '/Qu\\xe9bec/i'");
1476 : }
1477 :
1478 : // Tests that invalid flags are not accepted by the deserializer.
1479 15444 : TEST_F(ValueSerializerTest, DecodeRegExpDotAll) {
1480 : Local<Value> value =
1481 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x52, 0x03, 0x66, 0x6F, 0x6F, 0x1F});
1482 2 : ASSERT_TRUE(value->IsRegExp());
1483 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === RegExp.prototype");
1484 1 : ExpectScriptTrue("result.toString() === '/foo/gimuy'");
1485 :
1486 : value =
1487 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x52, 0x03, 0x66, 0x6F, 0x6F, 0x3F});
1488 2 : ASSERT_TRUE(value->IsRegExp());
1489 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === RegExp.prototype");
1490 1 : ExpectScriptTrue("result.toString() === '/foo/gimsuy'");
1491 :
1492 1 : InvalidDecodeTest(
1493 1 : {0xFF, 0x09, 0x3F, 0x00, 0x52, 0x03, 0x66, 0x6F, 0x6F, 0x7F});
1494 : }
1495 :
1496 15444 : TEST_F(ValueSerializerTest, RoundTripMap) {
1497 1 : Local<Value> value = RoundTripTest("var m = new Map(); m.set(42, 'foo'); m;");
1498 2 : ASSERT_TRUE(value->IsMap());
1499 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Map.prototype");
1500 1 : ExpectScriptTrue("result.size === 1");
1501 1 : ExpectScriptTrue("result.get(42) === 'foo'");
1502 :
1503 : value = RoundTripTest("var m = new Map(); m.set(m, m); m;");
1504 2 : ASSERT_TRUE(value->IsMap());
1505 1 : ExpectScriptTrue("result.size === 1");
1506 1 : ExpectScriptTrue("result.get(result) === result");
1507 :
1508 : // Iteration order must be preserved.
1509 : value = RoundTripTest(
1510 : "var m = new Map();"
1511 : "m.set(1, 0); m.set('a', 0); m.set(3, 0); m.set(2, 0);"
1512 : "m;");
1513 2 : ASSERT_TRUE(value->IsMap());
1514 1 : ExpectScriptTrue("Array.from(result.keys()).toString() === '1,a,3,2'");
1515 : }
1516 :
1517 15444 : TEST_F(ValueSerializerTest, DecodeMap) {
1518 : Local<Value> value =
1519 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3B, 0x3F, 0x01, 0x49, 0x54, 0x3F,
1520 2 : 0x01, 0x53, 0x03, 0x66, 0x6F, 0x6F, 0x3A, 0x02});
1521 2 : ASSERT_TRUE(value->IsMap());
1522 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Map.prototype");
1523 1 : ExpectScriptTrue("result.size === 1");
1524 1 : ExpectScriptTrue("result.get(42) === 'foo'");
1525 :
1526 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3B, 0x3F, 0x01, 0x5E, 0x00,
1527 2 : 0x3F, 0x01, 0x5E, 0x00, 0x3A, 0x02, 0x00});
1528 2 : ASSERT_TRUE(value->IsMap());
1529 1 : ExpectScriptTrue("result.size === 1");
1530 1 : ExpectScriptTrue("result.get(result) === result");
1531 :
1532 : // Iteration order must be preserved.
1533 : value =
1534 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3B, 0x3F, 0x01, 0x49, 0x02, 0x3F,
1535 : 0x01, 0x49, 0x00, 0x3F, 0x01, 0x53, 0x01, 0x61, 0x3F, 0x01,
1536 : 0x49, 0x00, 0x3F, 0x01, 0x49, 0x06, 0x3F, 0x01, 0x49, 0x00,
1537 2 : 0x3F, 0x01, 0x49, 0x04, 0x3F, 0x01, 0x49, 0x00, 0x3A, 0x08});
1538 2 : ASSERT_TRUE(value->IsMap());
1539 1 : ExpectScriptTrue("Array.from(result.keys()).toString() === '1,a,3,2'");
1540 : }
1541 :
1542 15444 : TEST_F(ValueSerializerTest, RoundTripMapWithTrickyGetters) {
1543 : // Even if an entry is removed or reassigned, the original key/value pair is
1544 : // used.
1545 : Local<Value> value = RoundTripTest(
1546 : "var m = new Map();"
1547 : "m.set(0, { get a() {"
1548 : " m.delete(1); m.set(2, 'baz'); m.set(3, 'quux');"
1549 : "}});"
1550 : "m.set(1, 'foo');"
1551 : "m.set(2, 'bar');"
1552 1 : "m;");
1553 2 : ASSERT_TRUE(value->IsMap());
1554 1 : ExpectScriptTrue("Array.from(result.keys()).toString() === '0,1,2'");
1555 1 : ExpectScriptTrue("result.get(1) === 'foo'");
1556 1 : ExpectScriptTrue("result.get(2) === 'bar'");
1557 :
1558 : // However, deeper modifications of objects yet to be serialized still apply.
1559 : value = RoundTripTest(
1560 : "var m = new Map();"
1561 : "var key = { get a() { value.foo = 'bar'; } };"
1562 : "var value = { get a() { key.baz = 'quux'; } };"
1563 : "m.set(key, value);"
1564 : "m;");
1565 2 : ASSERT_TRUE(value->IsMap());
1566 1 : ExpectScriptTrue("!('baz' in Array.from(result.keys())[0])");
1567 1 : ExpectScriptTrue("Array.from(result.values())[0].foo === 'bar'");
1568 : }
1569 :
1570 15444 : TEST_F(ValueSerializerTest, RoundTripSet) {
1571 : Local<Value> value =
1572 1 : RoundTripTest("var s = new Set(); s.add(42); s.add('foo'); s;");
1573 2 : ASSERT_TRUE(value->IsSet());
1574 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Set.prototype");
1575 1 : ExpectScriptTrue("result.size === 2");
1576 1 : ExpectScriptTrue("result.has(42)");
1577 1 : ExpectScriptTrue("result.has('foo')");
1578 :
1579 : value = RoundTripTest("var s = new Set(); s.add(s); s;");
1580 2 : ASSERT_TRUE(value->IsSet());
1581 1 : ExpectScriptTrue("result.size === 1");
1582 1 : ExpectScriptTrue("result.has(result)");
1583 :
1584 : // Iteration order must be preserved.
1585 : value = RoundTripTest(
1586 : "var s = new Set();"
1587 : "s.add(1); s.add('a'); s.add(3); s.add(2);"
1588 : "s;");
1589 2 : ASSERT_TRUE(value->IsSet());
1590 1 : ExpectScriptTrue("Array.from(result.keys()).toString() === '1,a,3,2'");
1591 : }
1592 :
1593 15444 : TEST_F(ValueSerializerTest, DecodeSet) {
1594 : Local<Value> value =
1595 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x27, 0x3F, 0x01, 0x49, 0x54, 0x3F,
1596 2 : 0x01, 0x53, 0x03, 0x66, 0x6F, 0x6F, 0x2C, 0x02});
1597 2 : ASSERT_TRUE(value->IsSet());
1598 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Set.prototype");
1599 1 : ExpectScriptTrue("result.size === 2");
1600 1 : ExpectScriptTrue("result.has(42)");
1601 1 : ExpectScriptTrue("result.has('foo')");
1602 :
1603 : value = DecodeTest(
1604 2 : {0xFF, 0x09, 0x3F, 0x00, 0x27, 0x3F, 0x01, 0x5E, 0x00, 0x2C, 0x01, 0x00});
1605 2 : ASSERT_TRUE(value->IsSet());
1606 1 : ExpectScriptTrue("result.size === 1");
1607 1 : ExpectScriptTrue("result.has(result)");
1608 :
1609 : // Iteration order must be preserved.
1610 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x27, 0x3F, 0x01, 0x49,
1611 : 0x02, 0x3F, 0x01, 0x53, 0x01, 0x61, 0x3F, 0x01,
1612 2 : 0x49, 0x06, 0x3F, 0x01, 0x49, 0x04, 0x2C, 0x04});
1613 2 : ASSERT_TRUE(value->IsSet());
1614 1 : ExpectScriptTrue("Array.from(result.keys()).toString() === '1,a,3,2'");
1615 : }
1616 :
1617 15444 : TEST_F(ValueSerializerTest, RoundTripSetWithTrickyGetters) {
1618 : // Even if an element is added or removed during serialization, the original
1619 : // set of elements is used.
1620 : Local<Value> value = RoundTripTest(
1621 : "var s = new Set();"
1622 : "s.add({ get a() { s.delete(1); s.add(2); } });"
1623 : "s.add(1);"
1624 1 : "s;");
1625 2 : ASSERT_TRUE(value->IsSet());
1626 : ExpectScriptTrue(
1627 1 : "Array.from(result.keys()).toString() === '[object Object],1'");
1628 :
1629 : // However, deeper modifications of objects yet to be serialized still apply.
1630 : value = RoundTripTest(
1631 : "var s = new Set();"
1632 : "var first = { get a() { second.foo = 'bar'; } };"
1633 : "var second = { get a() { first.baz = 'quux'; } };"
1634 : "s.add(first);"
1635 : "s.add(second);"
1636 : "s;");
1637 2 : ASSERT_TRUE(value->IsSet());
1638 1 : ExpectScriptTrue("!('baz' in Array.from(result.keys())[0])");
1639 1 : ExpectScriptTrue("Array.from(result.keys())[1].foo === 'bar'");
1640 : }
1641 :
1642 15444 : TEST_F(ValueSerializerTest, RoundTripArrayBuffer) {
1643 1 : Local<Value> value = RoundTripTest("new ArrayBuffer()");
1644 2 : ASSERT_TRUE(value->IsArrayBuffer());
1645 2 : EXPECT_EQ(0u, ArrayBuffer::Cast(*value)->ByteLength());
1646 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === ArrayBuffer.prototype");
1647 :
1648 : value = RoundTripTest("new Uint8Array([0, 128, 255]).buffer");
1649 2 : ASSERT_TRUE(value->IsArrayBuffer());
1650 2 : EXPECT_EQ(3u, ArrayBuffer::Cast(*value)->ByteLength());
1651 1 : ExpectScriptTrue("new Uint8Array(result).toString() === '0,128,255'");
1652 :
1653 : value =
1654 : RoundTripTest("({ a: new ArrayBuffer(), get b() { return this.a; }})");
1655 1 : ExpectScriptTrue("result.a instanceof ArrayBuffer");
1656 1 : ExpectScriptTrue("result.a === result.b");
1657 : }
1658 :
1659 15444 : TEST_F(ValueSerializerTest, DecodeArrayBuffer) {
1660 2 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x42, 0x00});
1661 2 : ASSERT_TRUE(value->IsArrayBuffer());
1662 2 : EXPECT_EQ(0u, ArrayBuffer::Cast(*value)->ByteLength());
1663 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === ArrayBuffer.prototype");
1664 :
1665 : value =
1666 2 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x42, 0x03, 0x00, 0x80, 0xFF, 0x00});
1667 2 : ASSERT_TRUE(value->IsArrayBuffer());
1668 2 : EXPECT_EQ(3u, ArrayBuffer::Cast(*value)->ByteLength());
1669 1 : ExpectScriptTrue("new Uint8Array(result).toString() === '0,128,255'");
1670 :
1671 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x01,
1672 : 0x61, 0x3F, 0x01, 0x42, 0x00, 0x3F, 0x02, 0x53, 0x01,
1673 2 : 0x62, 0x3F, 0x02, 0x5E, 0x01, 0x7B, 0x02, 0x00});
1674 1 : ExpectScriptTrue("result.a instanceof ArrayBuffer");
1675 1 : ExpectScriptTrue("result.a === result.b");
1676 : }
1677 :
1678 15444 : TEST_F(ValueSerializerTest, DecodeInvalidArrayBuffer) {
1679 2 : InvalidDecodeTest({0xFF, 0x09, 0x42, 0xFF, 0xFF, 0x00});
1680 1 : }
1681 :
1682 : // An array buffer allocator that never has available memory.
1683 1 : class OOMArrayBufferAllocator : public ArrayBuffer::Allocator {
1684 : public:
1685 0 : void* Allocate(size_t) override { return nullptr; }
1686 1 : void* AllocateUninitialized(size_t) override { return nullptr; }
1687 0 : void Free(void*, size_t) override {}
1688 : };
1689 :
1690 15444 : TEST_F(ValueSerializerTest, DecodeArrayBufferOOM) {
1691 : // This test uses less of the harness, because it has to customize the
1692 : // isolate.
1693 1 : OOMArrayBufferAllocator allocator;
1694 : Isolate::CreateParams params;
1695 1 : params.array_buffer_allocator = &allocator;
1696 1 : Isolate* isolate = Isolate::New(params);
1697 : {
1698 : Isolate::Scope isolate_scope(isolate);
1699 2 : HandleScope handle_scope(isolate);
1700 1 : Local<Context> context = Context::New(isolate);
1701 : Context::Scope context_scope(context);
1702 2 : TryCatch try_catch(isolate);
1703 :
1704 : const std::vector<uint8_t> data = {0xFF, 0x09, 0x3F, 0x00, 0x42,
1705 : 0x03, 0x00, 0x80, 0xFF, 0x00};
1706 : ValueDeserializer deserializer(isolate, &data[0],
1707 2 : static_cast<int>(data.size()), nullptr);
1708 1 : deserializer.SetSupportsLegacyWireFormat(true);
1709 2 : ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false));
1710 2 : ASSERT_FALSE(try_catch.HasCaught());
1711 2 : EXPECT_TRUE(deserializer.ReadValue(context).IsEmpty());
1712 2 : EXPECT_TRUE(try_catch.HasCaught());
1713 : }
1714 1 : isolate->Dispose();
1715 : }
1716 :
1717 : // Includes an ArrayBuffer wrapper marked for transfer from the serialization
1718 : // context to the deserialization context.
1719 2 : class ValueSerializerTestWithArrayBufferTransfer : public ValueSerializerTest {
1720 : protected:
1721 : static const size_t kTestByteLength = 4;
1722 :
1723 1 : ValueSerializerTestWithArrayBufferTransfer() {
1724 : {
1725 : Context::Scope scope(serialization_context());
1726 1 : input_buffer_ = ArrayBuffer::New(isolate(), nullptr, 0);
1727 : }
1728 : {
1729 : Context::Scope scope(deserialization_context());
1730 1 : output_buffer_ = ArrayBuffer::New(isolate(), kTestByteLength);
1731 1 : const uint8_t data[kTestByteLength] = {0x00, 0x01, 0x80, 0xFF};
1732 2 : memcpy(output_buffer_->GetContents().Data(), data, kTestByteLength);
1733 : }
1734 1 : }
1735 :
1736 : const Local<ArrayBuffer>& input_buffer() { return input_buffer_; }
1737 1 : const Local<ArrayBuffer>& output_buffer() { return output_buffer_; }
1738 :
1739 2 : void BeforeEncode(ValueSerializer* serializer) override {
1740 2 : serializer->TransferArrayBuffer(0, input_buffer_);
1741 2 : }
1742 :
1743 2 : void BeforeDecode(ValueDeserializer* deserializer) override {
1744 2 : deserializer->TransferArrayBuffer(0, output_buffer_);
1745 2 : }
1746 :
1747 : private:
1748 : Local<ArrayBuffer> input_buffer_;
1749 : Local<ArrayBuffer> output_buffer_;
1750 : };
1751 :
1752 15444 : TEST_F(ValueSerializerTestWithArrayBufferTransfer,
1753 : RoundTripArrayBufferTransfer) {
1754 1 : Local<Value> value = RoundTripTest(input_buffer());
1755 2 : ASSERT_TRUE(value->IsArrayBuffer());
1756 1 : EXPECT_EQ(output_buffer(), value);
1757 1 : ExpectScriptTrue("new Uint8Array(result).toString() === '0,1,128,255'");
1758 :
1759 : Local<Object> object;
1760 : {
1761 : Context::Scope scope(serialization_context());
1762 1 : object = Object::New(isolate());
1763 3 : EXPECT_TRUE(object
1764 : ->CreateDataProperty(serialization_context(),
1765 : StringFromUtf8("a"), input_buffer())
1766 0 : .FromMaybe(false));
1767 3 : EXPECT_TRUE(object
1768 : ->CreateDataProperty(serialization_context(),
1769 : StringFromUtf8("b"), input_buffer())
1770 0 : .FromMaybe(false));
1771 : }
1772 1 : value = RoundTripTest(object);
1773 1 : ExpectScriptTrue("result.a instanceof ArrayBuffer");
1774 1 : ExpectScriptTrue("result.a === result.b");
1775 1 : ExpectScriptTrue("new Uint8Array(result.a).toString() === '0,1,128,255'");
1776 : }
1777 :
1778 15444 : TEST_F(ValueSerializerTest, RoundTripTypedArray) {
1779 : // Check that the right type comes out the other side for every kind of typed
1780 : // array.
1781 : Local<Value> value;
1782 : #define TYPED_ARRAY_ROUND_TRIP_TEST(Type, type, TYPE, ctype) \
1783 : value = RoundTripTest("new " #Type "Array(2)"); \
1784 : ASSERT_TRUE(value->Is##Type##Array()); \
1785 : EXPECT_EQ(2u * sizeof(ctype), TypedArray::Cast(*value)->ByteLength()); \
1786 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length()); \
1787 : ExpectScriptTrue("Object.getPrototypeOf(result) === " #Type \
1788 : "Array.prototype");
1789 :
1790 78 : TYPED_ARRAYS(TYPED_ARRAY_ROUND_TRIP_TEST)
1791 : #undef TYPED_ARRAY_ROUND_TRIP_TEST
1792 :
1793 : // Check that values of various kinds are suitably preserved.
1794 : value = RoundTripTest("new Uint8Array([1, 128, 255])");
1795 1 : ExpectScriptTrue("result.toString() === '1,128,255'");
1796 :
1797 : value = RoundTripTest("new Int16Array([0, 256, -32768])");
1798 1 : ExpectScriptTrue("result.toString() === '0,256,-32768'");
1799 :
1800 : value = RoundTripTest("new Float32Array([0, -0.5, NaN, Infinity])");
1801 1 : ExpectScriptTrue("result.toString() === '0,-0.5,NaN,Infinity'");
1802 :
1803 : // Array buffer views sharing a buffer should do so on the other side.
1804 : // Similarly, multiple references to the same typed array should be resolved.
1805 : value = RoundTripTest(
1806 : "var buffer = new ArrayBuffer(32);"
1807 : "({"
1808 : " u8: new Uint8Array(buffer),"
1809 : " get u8_2() { return this.u8; },"
1810 : " f32: new Float32Array(buffer, 4, 5),"
1811 : " b: buffer,"
1812 : "});");
1813 1 : ExpectScriptTrue("result.u8 instanceof Uint8Array");
1814 1 : ExpectScriptTrue("result.u8 === result.u8_2");
1815 1 : ExpectScriptTrue("result.f32 instanceof Float32Array");
1816 1 : ExpectScriptTrue("result.u8.buffer === result.f32.buffer");
1817 1 : ExpectScriptTrue("result.f32.byteOffset === 4");
1818 1 : ExpectScriptTrue("result.f32.length === 5");
1819 : }
1820 :
1821 15444 : TEST_F(ValueSerializerTest, DecodeTypedArray) {
1822 : // Check that the right type comes out the other side for every kind of typed
1823 : // array.
1824 : Local<Value> value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42,
1825 2 : 0x02, 0x00, 0x00, 0x56, 0x42, 0x00, 0x02});
1826 2 : ASSERT_TRUE(value->IsUint8Array());
1827 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->ByteLength());
1828 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1829 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Uint8Array.prototype");
1830 :
1831 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x02, 0x00,
1832 2 : 0x00, 0x56, 0x62, 0x00, 0x02});
1833 2 : ASSERT_TRUE(value->IsInt8Array());
1834 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->ByteLength());
1835 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1836 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Int8Array.prototype");
1837 :
1838 : #if defined(V8_TARGET_LITTLE_ENDIAN)
1839 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00,
1840 2 : 0x00, 0x00, 0x00, 0x56, 0x57, 0x00, 0x04});
1841 2 : ASSERT_TRUE(value->IsUint16Array());
1842 2 : EXPECT_EQ(4u, TypedArray::Cast(*value)->ByteLength());
1843 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1844 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Uint16Array.prototype");
1845 :
1846 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00,
1847 2 : 0x00, 0x00, 0x00, 0x56, 0x77, 0x00, 0x04});
1848 2 : ASSERT_TRUE(value->IsInt16Array());
1849 2 : EXPECT_EQ(4u, TypedArray::Cast(*value)->ByteLength());
1850 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1851 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Int16Array.prototype");
1852 :
1853 : value =
1854 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
1855 2 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x44, 0x00, 0x08});
1856 2 : ASSERT_TRUE(value->IsUint32Array());
1857 2 : EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
1858 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1859 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Uint32Array.prototype");
1860 :
1861 : value =
1862 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
1863 2 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x64, 0x00, 0x08});
1864 2 : ASSERT_TRUE(value->IsInt32Array());
1865 2 : EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
1866 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1867 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Int32Array.prototype");
1868 :
1869 : value =
1870 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x08, 0x00, 0x00,
1871 2 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x66, 0x00, 0x08});
1872 2 : ASSERT_TRUE(value->IsFloat32Array());
1873 2 : EXPECT_EQ(8u, TypedArray::Cast(*value)->ByteLength());
1874 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1875 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Float32Array.prototype");
1876 :
1877 : value =
1878 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x10, 0x00, 0x00,
1879 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1880 2 : 0x00, 0x00, 0x00, 0x00, 0x56, 0x46, 0x00, 0x10});
1881 2 : ASSERT_TRUE(value->IsFloat64Array());
1882 2 : EXPECT_EQ(16u, TypedArray::Cast(*value)->ByteLength());
1883 2 : EXPECT_EQ(2u, TypedArray::Cast(*value)->Length());
1884 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === Float64Array.prototype");
1885 :
1886 : #endif // V8_TARGET_LITTLE_ENDIAN
1887 :
1888 : // Check that values of various kinds are suitably preserved.
1889 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x03, 0x01,
1890 2 : 0x80, 0xFF, 0x56, 0x42, 0x00, 0x03, 0x00});
1891 1 : ExpectScriptTrue("result.toString() === '1,128,255'");
1892 :
1893 : #if defined(V8_TARGET_LITTLE_ENDIAN)
1894 : value = DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x06, 0x00,
1895 2 : 0x00, 0x00, 0x01, 0x00, 0x80, 0x56, 0x77, 0x00, 0x06});
1896 1 : ExpectScriptTrue("result.toString() === '0,256,-32768'");
1897 :
1898 : value =
1899 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x10, 0x00, 0x00,
1900 : 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0xC0, 0x7F,
1901 2 : 0x00, 0x00, 0x80, 0x7F, 0x56, 0x66, 0x00, 0x10});
1902 1 : ExpectScriptTrue("result.toString() === '0,-0.5,NaN,Infinity'");
1903 :
1904 : #endif // V8_TARGET_LITTLE_ENDIAN
1905 :
1906 : // Array buffer views sharing a buffer should do so on the other side.
1907 : // Similarly, multiple references to the same typed array should be resolved.
1908 : value = DecodeTest(
1909 : {0xFF, 0x09, 0x3F, 0x00, 0x6F, 0x3F, 0x01, 0x53, 0x02, 0x75, 0x38, 0x3F,
1910 : 0x01, 0x3F, 0x01, 0x42, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1911 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1912 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1913 : 0x00, 0x56, 0x42, 0x00, 0x20, 0x3F, 0x03, 0x53, 0x04, 0x75, 0x38, 0x5F,
1914 : 0x32, 0x3F, 0x03, 0x5E, 0x02, 0x3F, 0x03, 0x53, 0x03, 0x66, 0x33, 0x32,
1915 : 0x3F, 0x03, 0x3F, 0x03, 0x5E, 0x01, 0x56, 0x66, 0x04, 0x14, 0x3F, 0x04,
1916 2 : 0x53, 0x01, 0x62, 0x3F, 0x04, 0x5E, 0x01, 0x7B, 0x04, 0x00});
1917 1 : ExpectScriptTrue("result.u8 instanceof Uint8Array");
1918 1 : ExpectScriptTrue("result.u8 === result.u8_2");
1919 1 : ExpectScriptTrue("result.f32 instanceof Float32Array");
1920 1 : ExpectScriptTrue("result.u8.buffer === result.f32.buffer");
1921 1 : ExpectScriptTrue("result.f32.byteOffset === 4");
1922 1 : ExpectScriptTrue("result.f32.length === 5");
1923 : }
1924 :
1925 15444 : TEST_F(ValueSerializerTest, DecodeInvalidTypedArray) {
1926 : // Byte offset out of range.
1927 2 : InvalidDecodeTest(
1928 1 : {0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0x42, 0x03, 0x01});
1929 : // Byte offset in range, offset + length out of range.
1930 1 : InvalidDecodeTest(
1931 1 : {0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0x42, 0x01, 0x03});
1932 : // Byte offset not divisible by element size.
1933 1 : InvalidDecodeTest(
1934 1 : {0xFF, 0x09, 0x42, 0x04, 0x00, 0x00, 0x00, 0x00, 0x56, 0x77, 0x01, 0x02});
1935 : // Byte length not divisible by element size.
1936 1 : InvalidDecodeTest(
1937 1 : {0xFF, 0x09, 0x42, 0x04, 0x00, 0x00, 0x00, 0x00, 0x56, 0x77, 0x02, 0x01});
1938 : // Invalid view type (0xFF).
1939 1 : InvalidDecodeTest(
1940 1 : {0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0xFF, 0x01, 0x01});
1941 1 : }
1942 :
1943 15444 : TEST_F(ValueSerializerTest, RoundTripDataView) {
1944 1 : Local<Value> value = RoundTripTest("new DataView(new ArrayBuffer(4), 1, 2)");
1945 2 : ASSERT_TRUE(value->IsDataView());
1946 2 : EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset());
1947 2 : EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength());
1948 3 : EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength());
1949 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === DataView.prototype");
1950 : }
1951 :
1952 15444 : TEST_F(ValueSerializerTest, DecodeDataView) {
1953 : Local<Value> value =
1954 : DecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x3F, 0x00, 0x42, 0x04, 0x00, 0x00,
1955 2 : 0x00, 0x00, 0x56, 0x3F, 0x01, 0x02});
1956 2 : ASSERT_TRUE(value->IsDataView());
1957 2 : EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset());
1958 2 : EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength());
1959 3 : EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength());
1960 1 : ExpectScriptTrue("Object.getPrototypeOf(result) === DataView.prototype");
1961 : }
1962 :
1963 15444 : TEST_F(ValueSerializerTest, DecodeArrayWithLengthProperty1) {
1964 2 : InvalidDecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04,
1965 : 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67,
1966 1 : 0x74, 0x68, 0x49, 0x02, 0x24, 0x01, 0x03});
1967 1 : }
1968 :
1969 15444 : TEST_F(ValueSerializerTest, DecodeArrayWithLengthProperty2) {
1970 2 : InvalidDecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04,
1971 : 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67,
1972 1 : 0x74, 0x68, 0x6f, 0x7b, 0x00, 0x24, 0x01, 0x03});
1973 1 : }
1974 :
1975 15444 : TEST_F(ValueSerializerTest, DecodeInvalidDataView) {
1976 : // Byte offset out of range.
1977 2 : InvalidDecodeTest(
1978 1 : {0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0x3F, 0x03, 0x01});
1979 : // Byte offset in range, offset + length out of range.
1980 1 : InvalidDecodeTest(
1981 1 : {0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0x3F, 0x01, 0x03});
1982 1 : }
1983 :
1984 4 : class ValueSerializerTestWithSharedArrayBufferClone
1985 : : public ValueSerializerTest {
1986 : protected:
1987 2 : ValueSerializerTestWithSharedArrayBufferClone()
1988 4 : : serializer_delegate_(this), deserializer_delegate_(this) {}
1989 :
1990 2 : void InitializeData(const std::vector<uint8_t>& data) {
1991 2 : data_ = data;
1992 : {
1993 : Context::Scope scope(serialization_context());
1994 : input_buffer_ =
1995 2 : SharedArrayBuffer::New(isolate(), data_.data(), data_.size());
1996 : }
1997 : {
1998 : Context::Scope scope(deserialization_context());
1999 : output_buffer_ =
2000 2 : SharedArrayBuffer::New(isolate(), data_.data(), data_.size());
2001 : }
2002 2 : }
2003 :
2004 2 : const Local<SharedArrayBuffer>& input_buffer() { return input_buffer_; }
2005 1 : const Local<SharedArrayBuffer>& output_buffer() { return output_buffer_; }
2006 :
2007 2 : static void SetUpTestCase() {
2008 2 : flag_was_enabled_ = i::FLAG_harmony_sharedarraybuffer;
2009 2 : i::FLAG_harmony_sharedarraybuffer = true;
2010 : ValueSerializerTest::SetUpTestCase();
2011 2 : }
2012 :
2013 2 : static void TearDownTestCase() {
2014 : ValueSerializerTest::TearDownTestCase();
2015 2 : i::FLAG_harmony_sharedarraybuffer = flag_was_enabled_;
2016 2 : flag_was_enabled_ = false;
2017 2 : }
2018 :
2019 : protected:
2020 : // GMock doesn't use the "override" keyword.
2021 : #if __clang__
2022 : #pragma clang diagnostic push
2023 : #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2024 : #endif
2025 :
2026 4 : class SerializerDelegate : public ValueSerializer::Delegate {
2027 : public:
2028 : explicit SerializerDelegate(
2029 : ValueSerializerTestWithSharedArrayBufferClone* test)
2030 4 : : test_(test) {}
2031 11 : MOCK_METHOD2(GetSharedArrayBufferId,
2032 : Maybe<uint32_t>(Isolate* isolate,
2033 : Local<SharedArrayBuffer> shared_array_buffer));
2034 : MOCK_METHOD2(GetSharedArrayBufferFromId,
2035 : MaybeLocal<SharedArrayBuffer>(Isolate* isolate, uint32_t id));
2036 0 : void ThrowDataCloneError(Local<String> message) override {
2037 0 : test_->isolate()->ThrowException(Exception::Error(message));
2038 0 : }
2039 :
2040 : private:
2041 : ValueSerializerTestWithSharedArrayBufferClone* test_;
2042 : };
2043 :
2044 4 : class DeserializerDelegate : public ValueDeserializer::Delegate {
2045 : public:
2046 : explicit DeserializerDelegate(
2047 2 : ValueSerializerTestWithSharedArrayBufferClone* test) {}
2048 11 : MOCK_METHOD2(GetSharedArrayBufferFromId,
2049 : MaybeLocal<SharedArrayBuffer>(Isolate* isolate, uint32_t id));
2050 : };
2051 :
2052 : #if __clang__
2053 : #pragma clang diagnostic pop
2054 : #endif
2055 :
2056 6 : ValueSerializer::Delegate* GetSerializerDelegate() override {
2057 6 : return &serializer_delegate_;
2058 : }
2059 :
2060 3 : ValueDeserializer::Delegate* GetDeserializerDelegate() override {
2061 3 : return &deserializer_delegate_;
2062 : }
2063 :
2064 : SerializerDelegate serializer_delegate_;
2065 : DeserializerDelegate deserializer_delegate_;
2066 :
2067 : private:
2068 : static bool flag_was_enabled_;
2069 : std::vector<uint8_t> data_;
2070 : Local<SharedArrayBuffer> input_buffer_;
2071 : Local<SharedArrayBuffer> output_buffer_;
2072 : };
2073 :
2074 : bool ValueSerializerTestWithSharedArrayBufferClone::flag_was_enabled_ = false;
2075 :
2076 15443 : TEST_F(ValueSerializerTestWithSharedArrayBufferClone,
2077 : RoundTripSharedArrayBufferClone) {
2078 2 : InitializeData({0x00, 0x01, 0x80, 0xFF});
2079 :
2080 6 : EXPECT_CALL(serializer_delegate_,
2081 : GetSharedArrayBufferId(isolate(), input_buffer()))
2082 4 : .WillRepeatedly(Return(Just(0U)));
2083 5 : EXPECT_CALL(deserializer_delegate_, GetSharedArrayBufferFromId(isolate(), 0U))
2084 4 : .WillRepeatedly(Return(output_buffer()));
2085 :
2086 1 : Local<Value> value = RoundTripTest(input_buffer());
2087 2 : ASSERT_TRUE(value->IsSharedArrayBuffer());
2088 1 : EXPECT_EQ(output_buffer(), value);
2089 1 : ExpectScriptTrue("new Uint8Array(result).toString() === '0,1,128,255'");
2090 :
2091 : Local<Object> object;
2092 : {
2093 : Context::Scope scope(serialization_context());
2094 1 : object = Object::New(isolate());
2095 3 : EXPECT_TRUE(object
2096 : ->CreateDataProperty(serialization_context(),
2097 : StringFromUtf8("a"), input_buffer())
2098 0 : .FromMaybe(false));
2099 3 : EXPECT_TRUE(object
2100 : ->CreateDataProperty(serialization_context(),
2101 : StringFromUtf8("b"), input_buffer())
2102 0 : .FromMaybe(false));
2103 : }
2104 1 : value = RoundTripTest(object);
2105 1 : ExpectScriptTrue("result.a instanceof SharedArrayBuffer");
2106 1 : ExpectScriptTrue("result.a === result.b");
2107 1 : ExpectScriptTrue("new Uint8Array(result.a).toString() === '0,1,128,255'");
2108 : }
2109 :
2110 15443 : TEST_F(ValueSerializerTestWithSharedArrayBufferClone,
2111 : RoundTripWebAssemblyMemory) {
2112 1 : bool flag_was_enabled = i::FLAG_experimental_wasm_threads;
2113 1 : i::FLAG_experimental_wasm_threads = true;
2114 :
2115 : std::vector<uint8_t> data = {0x00, 0x01, 0x80, 0xFF};
2116 1 : data.resize(65536);
2117 1 : InitializeData(data);
2118 :
2119 6 : EXPECT_CALL(serializer_delegate_,
2120 : GetSharedArrayBufferId(isolate(), input_buffer()))
2121 4 : .WillRepeatedly(Return(Just(0U)));
2122 5 : EXPECT_CALL(deserializer_delegate_, GetSharedArrayBufferFromId(isolate(), 0U))
2123 4 : .WillRepeatedly(Return(output_buffer()));
2124 :
2125 : Local<Value> input;
2126 : {
2127 : Context::Scope scope(serialization_context());
2128 : const int32_t kMaxPages = 1;
2129 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate());
2130 : i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(*input_buffer());
2131 : input = Utils::Convert<i::WasmMemoryObject, Value>(
2132 1 : i::WasmMemoryObject::New(i_isolate, obj, kMaxPages));
2133 : }
2134 1 : RoundTripTest(input);
2135 1 : ExpectScriptTrue("result instanceof WebAssembly.Memory");
2136 1 : ExpectScriptTrue("result.buffer.byteLength === 65536");
2137 : ExpectScriptTrue(
2138 1 : "new Uint8Array(result.buffer, 0, 4).toString() === '0,1,128,255'");
2139 :
2140 1 : i::FLAG_experimental_wasm_threads = flag_was_enabled;
2141 1 : }
2142 :
2143 15444 : TEST_F(ValueSerializerTest, UnsupportedHostObject) {
2144 1 : InvalidEncodeTest("new ExampleHostObject()");
2145 : InvalidEncodeTest("({ a: new ExampleHostObject() })");
2146 1 : }
2147 :
2148 14 : class ValueSerializerTestWithHostObject : public ValueSerializerTest {
2149 : protected:
2150 14 : ValueSerializerTestWithHostObject() : serializer_delegate_(this) {}
2151 :
2152 : static const uint8_t kExampleHostObjectTag;
2153 :
2154 : void WriteExampleHostObjectTag() {
2155 11 : serializer_->WriteRawBytes(&kExampleHostObjectTag, 1);
2156 : }
2157 :
2158 12 : bool ReadExampleHostObjectTag() {
2159 : const void* tag;
2160 24 : return deserializer_->ReadRawBytes(1, &tag) &&
2161 24 : *reinterpret_cast<const uint8_t*>(tag) == kExampleHostObjectTag;
2162 : }
2163 :
2164 : // GMock doesn't use the "override" keyword.
2165 : #if __clang__
2166 : #pragma clang diagnostic push
2167 : #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2168 : #endif
2169 :
2170 14 : class SerializerDelegate : public ValueSerializer::Delegate {
2171 : public:
2172 : explicit SerializerDelegate(ValueSerializerTestWithHostObject* test)
2173 14 : : test_(test) {}
2174 35 : MOCK_METHOD2(WriteHostObject,
2175 : Maybe<bool>(Isolate* isolate, Local<Object> object));
2176 0 : void ThrowDataCloneError(Local<String> message) override {
2177 0 : test_->isolate()->ThrowException(Exception::Error(message));
2178 0 : }
2179 :
2180 : private:
2181 : ValueSerializerTestWithHostObject* test_;
2182 : };
2183 :
2184 21 : class DeserializerDelegate : public ValueDeserializer::Delegate {
2185 : public:
2186 33 : MOCK_METHOD1(ReadHostObject, MaybeLocal<Object>(Isolate* isolate));
2187 : };
2188 :
2189 : #if __clang__
2190 : #pragma clang diagnostic pop
2191 : #endif
2192 :
2193 22 : ValueSerializer::Delegate* GetSerializerDelegate() override {
2194 22 : return &serializer_delegate_;
2195 : }
2196 10 : void BeforeEncode(ValueSerializer* serializer) override {
2197 11 : serializer_ = serializer;
2198 10 : }
2199 12 : ValueDeserializer::Delegate* GetDeserializerDelegate() override {
2200 12 : return &deserializer_delegate_;
2201 : }
2202 12 : void BeforeDecode(ValueDeserializer* deserializer) override {
2203 12 : deserializer_ = deserializer;
2204 12 : }
2205 :
2206 : SerializerDelegate serializer_delegate_;
2207 : DeserializerDelegate deserializer_delegate_;
2208 : ValueSerializer* serializer_;
2209 : ValueDeserializer* deserializer_;
2210 :
2211 : friend class SerializerDelegate;
2212 : friend class DeserializerDelegate;
2213 : };
2214 :
2215 : // This is a tag that is used in V8. Using this ensures that we have separate
2216 : // tag namespaces.
2217 : const uint8_t ValueSerializerTestWithHostObject::kExampleHostObjectTag = 'T';
2218 :
2219 15443 : TEST_F(ValueSerializerTestWithHostObject, RoundTripUint32) {
2220 : // The host can serialize data as uint32_t.
2221 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2222 6 : .WillRepeatedly(Invoke([this](Isolate*, Local<Object> object) {
2223 : uint32_t value = 0;
2224 4 : EXPECT_TRUE(object->GetInternalField(0)
2225 : ->Uint32Value(serialization_context())
2226 0 : .To(&value));
2227 : WriteExampleHostObjectTag();
2228 2 : serializer_->WriteUint32(value);
2229 2 : return Just(true);
2230 2 : }));
2231 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2232 6 : .WillRepeatedly(Invoke([this](Isolate*) {
2233 4 : EXPECT_TRUE(ReadExampleHostObjectTag());
2234 2 : uint32_t value = 0;
2235 4 : EXPECT_TRUE(deserializer_->ReadUint32(&value));
2236 4 : Local<Value> argv[] = {Integer::NewFromUnsigned(isolate(), value)};
2237 2 : return NewHostObject(deserialization_context(), arraysize(argv), argv);
2238 2 : }));
2239 1 : Local<Value> value = RoundTripTest("new ExampleHostObject(42)");
2240 2 : ASSERT_TRUE(value->IsObject());
2241 2 : ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount());
2242 : ExpectScriptTrue(
2243 1 : "Object.getPrototypeOf(result) === ExampleHostObject.prototype");
2244 1 : ExpectScriptTrue("result.value === 42");
2245 :
2246 : value = RoundTripTest("new ExampleHostObject(0xCAFECAFE)");
2247 1 : ExpectScriptTrue("result.value === 0xCAFECAFE");
2248 : }
2249 :
2250 15443 : TEST_F(ValueSerializerTestWithHostObject, RoundTripUint64) {
2251 : // The host can serialize data as uint64_t.
2252 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2253 8 : .WillRepeatedly(Invoke([this](Isolate*, Local<Object> object) {
2254 : uint32_t value = 0, value2 = 0;
2255 4 : EXPECT_TRUE(object->GetInternalField(0)
2256 : ->Uint32Value(serialization_context())
2257 0 : .To(&value));
2258 4 : EXPECT_TRUE(object->GetInternalField(1)
2259 : ->Uint32Value(serialization_context())
2260 0 : .To(&value2));
2261 : WriteExampleHostObjectTag();
2262 4 : serializer_->WriteUint64((static_cast<uint64_t>(value) << 32) | value2);
2263 2 : return Just(true);
2264 2 : }));
2265 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2266 6 : .WillRepeatedly(Invoke([this](Isolate*) {
2267 4 : EXPECT_TRUE(ReadExampleHostObjectTag());
2268 : uint64_t value_packed;
2269 4 : EXPECT_TRUE(deserializer_->ReadUint64(&value_packed));
2270 : Local<Value> argv[] = {
2271 : Integer::NewFromUnsigned(isolate(),
2272 2 : static_cast<uint32_t>(value_packed >> 32)),
2273 : Integer::NewFromUnsigned(isolate(),
2274 8 : static_cast<uint32_t>(value_packed))};
2275 2 : return NewHostObject(deserialization_context(), arraysize(argv), argv);
2276 2 : }));
2277 1 : Local<Value> value = RoundTripTest("new ExampleHostObject(42, 0)");
2278 2 : ASSERT_TRUE(value->IsObject());
2279 2 : ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount());
2280 : ExpectScriptTrue(
2281 1 : "Object.getPrototypeOf(result) === ExampleHostObject.prototype");
2282 1 : ExpectScriptTrue("result.value === 42");
2283 1 : ExpectScriptTrue("result.value2 === 0");
2284 :
2285 : value = RoundTripTest("new ExampleHostObject(0xFFFFFFFF, 0x12345678)");
2286 1 : ExpectScriptTrue("result.value === 0xFFFFFFFF");
2287 1 : ExpectScriptTrue("result.value2 === 0x12345678");
2288 : }
2289 :
2290 15443 : TEST_F(ValueSerializerTestWithHostObject, RoundTripDouble) {
2291 : // The host can serialize data as double.
2292 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2293 12 : .WillRepeatedly(Invoke([this](Isolate*, Local<Object> object) {
2294 : double value = 0;
2295 8 : EXPECT_TRUE(object->GetInternalField(0)
2296 : ->NumberValue(serialization_context())
2297 0 : .To(&value));
2298 : WriteExampleHostObjectTag();
2299 4 : serializer_->WriteDouble(value);
2300 4 : return Just(true);
2301 2 : }));
2302 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2303 12 : .WillRepeatedly(Invoke([this](Isolate*) {
2304 8 : EXPECT_TRUE(ReadExampleHostObjectTag());
2305 4 : double value = 0;
2306 8 : EXPECT_TRUE(deserializer_->ReadDouble(&value));
2307 8 : Local<Value> argv[] = {Number::New(isolate(), value)};
2308 4 : return NewHostObject(deserialization_context(), arraysize(argv), argv);
2309 2 : }));
2310 1 : Local<Value> value = RoundTripTest("new ExampleHostObject(-3.5)");
2311 2 : ASSERT_TRUE(value->IsObject());
2312 2 : ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount());
2313 : ExpectScriptTrue(
2314 1 : "Object.getPrototypeOf(result) === ExampleHostObject.prototype");
2315 1 : ExpectScriptTrue("result.value === -3.5");
2316 :
2317 : value = RoundTripTest("new ExampleHostObject(NaN)");
2318 1 : ExpectScriptTrue("Number.isNaN(result.value)");
2319 :
2320 : value = RoundTripTest("new ExampleHostObject(Infinity)");
2321 1 : ExpectScriptTrue("result.value === Infinity");
2322 :
2323 : value = RoundTripTest("new ExampleHostObject(-0)");
2324 1 : ExpectScriptTrue("1/result.value === -Infinity");
2325 : }
2326 :
2327 15443 : TEST_F(ValueSerializerTestWithHostObject, RoundTripRawBytes) {
2328 : // The host can serialize arbitrary raw bytes.
2329 : const struct {
2330 : uint64_t u64;
2331 : uint32_t u32;
2332 : char str[12];
2333 1 : } sample_data = {0x1234567812345678, 0x87654321, "Hello world"};
2334 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2335 : .WillRepeatedly(
2336 2 : Invoke([this, &sample_data](Isolate*, Local<Object> object) {
2337 : WriteExampleHostObjectTag();
2338 1 : serializer_->WriteRawBytes(&sample_data, sizeof(sample_data));
2339 1 : return Just(true);
2340 2 : }));
2341 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2342 4 : .WillRepeatedly(Invoke([this, &sample_data](Isolate*) {
2343 2 : EXPECT_TRUE(ReadExampleHostObjectTag());
2344 1 : const void* copied_data = nullptr;
2345 2 : EXPECT_TRUE(
2346 0 : deserializer_->ReadRawBytes(sizeof(sample_data), &copied_data));
2347 1 : if (copied_data) {
2348 2 : EXPECT_EQ(0, memcmp(&sample_data, copied_data, sizeof(sample_data)));
2349 : }
2350 1 : return NewHostObject(deserialization_context(), 0, nullptr);
2351 2 : }));
2352 1 : Local<Value> value = RoundTripTest("new ExampleHostObject()");
2353 2 : ASSERT_TRUE(value->IsObject());
2354 2 : ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount());
2355 : ExpectScriptTrue(
2356 1 : "Object.getPrototypeOf(result) === ExampleHostObject.prototype");
2357 : }
2358 :
2359 15443 : TEST_F(ValueSerializerTestWithHostObject, RoundTripSameObject) {
2360 : // If the same object exists in two places, the delegate should be invoked
2361 : // only once, and the objects should be the same (by reference equality) on
2362 : // the other side.
2363 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2364 1 : .WillOnce(Invoke([this](Isolate*, Local<Object> object) {
2365 : WriteExampleHostObjectTag();
2366 : return Just(true);
2367 2 : }));
2368 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2369 2 : .WillOnce(Invoke([this](Isolate*) {
2370 2 : EXPECT_TRUE(ReadExampleHostObjectTag());
2371 1 : return NewHostObject(deserialization_context(), 0, nullptr);
2372 2 : }));
2373 1 : RoundTripTest("({ a: new ExampleHostObject(), get b() { return this.a; }})");
2374 1 : ExpectScriptTrue("result.a instanceof ExampleHostObject");
2375 1 : ExpectScriptTrue("result.a === result.b");
2376 1 : }
2377 :
2378 15443 : TEST_F(ValueSerializerTestWithHostObject, DecodeSimpleHostObject) {
2379 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2380 2 : .WillRepeatedly(Invoke([this](Isolate*) {
2381 2 : EXPECT_TRUE(ReadExampleHostObjectTag());
2382 1 : return NewHostObject(deserialization_context(), 0, nullptr);
2383 2 : }));
2384 2 : DecodeTest({0xFF, 0x0D, 0x5C, kExampleHostObjectTag});
2385 : ExpectScriptTrue(
2386 1 : "Object.getPrototypeOf(result) === ExampleHostObject.prototype");
2387 1 : }
2388 :
2389 2 : class ValueSerializerTestWithHostArrayBufferView
2390 : : public ValueSerializerTestWithHostObject {
2391 : protected:
2392 1 : void BeforeEncode(ValueSerializer* serializer) override {
2393 : ValueSerializerTestWithHostObject::BeforeEncode(serializer);
2394 1 : serializer_->SetTreatArrayBufferViewsAsHostObjects(true);
2395 1 : }
2396 : };
2397 :
2398 15444 : TEST_F(ValueSerializerTestWithHostArrayBufferView, RoundTripUint8ArrayInput) {
2399 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2400 2 : .WillOnce(Invoke([this](Isolate*, Local<Object> object) {
2401 2 : EXPECT_TRUE(object->IsUint8Array());
2402 : WriteExampleHostObjectTag();
2403 1 : return Just(true);
2404 2 : }));
2405 4 : EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
2406 1 : .WillOnce(Invoke([this](Isolate*) {
2407 2 : EXPECT_TRUE(ReadExampleHostObjectTag());
2408 1 : return NewDummyUint8Array();
2409 2 : }));
2410 : RoundTripTest(
2411 1 : "({ a: new Uint8Array([1, 2, 3]), get b() { return this.a; }})");
2412 1 : ExpectScriptTrue("result.a instanceof Uint8Array");
2413 1 : ExpectScriptTrue("result.a.toString() === '4,5,6'");
2414 1 : ExpectScriptTrue("result.a === result.b");
2415 1 : }
2416 :
2417 : // It's expected that WebAssembly has more exhaustive tests elsewhere; this
2418 : // mostly checks that the logic to embed it in structured clone serialization
2419 : // works correctly.
2420 :
2421 : // A simple module which exports an "increment" function.
2422 : // Copied from test/mjsunit/wasm/incrementer.wasm.
2423 : const unsigned char kIncrementerWasm[] = {
2424 : 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127,
2425 : 3, 2, 1, 0, 7, 13, 1, 9, 105, 110, 99, 114, 101, 109, 101, 110,
2426 : 116, 0, 0, 10, 9, 1, 7, 0, 32, 0, 65, 1, 106, 11,
2427 : };
2428 :
2429 42 : class ValueSerializerTestWithWasm : public ValueSerializerTest {
2430 : public:
2431 : static const char* kUnsupportedSerialization;
2432 :
2433 14 : ValueSerializerTestWithWasm()
2434 : : serialize_delegate_(&transfer_modules_),
2435 56 : deserialize_delegate_(&transfer_modules_) {}
2436 :
2437 : void Reset() {
2438 : current_serializer_delegate_ = nullptr;
2439 : transfer_modules_.clear();
2440 : SetExpectInlineWasm(false);
2441 : }
2442 :
2443 : void EnableTransferSerialization() {
2444 5 : current_serializer_delegate_ = &serialize_delegate_;
2445 : }
2446 :
2447 : void EnableTransferDeserialization() {
2448 3 : current_deserializer_delegate_ = &deserialize_delegate_;
2449 : }
2450 :
2451 : void EnableThrowingSerializer() {
2452 1 : current_serializer_delegate_ = &throwing_serializer_;
2453 : }
2454 :
2455 : void EnableDefaultDeserializer() {
2456 1 : current_deserializer_delegate_ = &default_deserializer_;
2457 : }
2458 :
2459 : protected:
2460 14 : static void SetUpTestCase() {
2461 14 : g_saved_flag = i::FLAG_expose_wasm;
2462 14 : i::FLAG_expose_wasm = true;
2463 : ValueSerializerTest::SetUpTestCase();
2464 14 : }
2465 :
2466 14 : static void TearDownTestCase() {
2467 : ValueSerializerTest::TearDownTestCase();
2468 14 : i::FLAG_expose_wasm = g_saved_flag;
2469 14 : g_saved_flag = false;
2470 14 : }
2471 :
2472 42 : class ThrowingSerializer : public ValueSerializer::Delegate {
2473 : public:
2474 1 : Maybe<uint32_t> GetWasmModuleTransferId(
2475 : Isolate* isolate, Local<WasmModuleObject> module) override {
2476 : isolate->ThrowException(Exception::Error(
2477 1 : String::NewFromOneByte(
2478 : isolate,
2479 : reinterpret_cast<const uint8_t*>(kUnsupportedSerialization),
2480 1 : NewStringType::kNormal)
2481 1 : .ToLocalChecked()));
2482 1 : return Nothing<uint32_t>();
2483 : }
2484 :
2485 0 : void ThrowDataCloneError(Local<String> message) override { UNREACHABLE(); }
2486 : };
2487 :
2488 28 : class SerializeToTransfer : public ValueSerializer::Delegate {
2489 : public:
2490 : SerializeToTransfer(
2491 : std::vector<WasmModuleObject::TransferrableModule>* modules)
2492 14 : : modules_(modules) {}
2493 6 : Maybe<uint32_t> GetWasmModuleTransferId(
2494 : Isolate* isolate, Local<WasmModuleObject> module) override {
2495 12 : modules_->push_back(module->GetTransferrableModule());
2496 12 : return Just(static_cast<uint32_t>(modules_->size()) - 1);
2497 : }
2498 :
2499 0 : void ThrowDataCloneError(Local<String> message) override { UNREACHABLE(); }
2500 :
2501 : private:
2502 : std::vector<WasmModuleObject::TransferrableModule>* modules_;
2503 : };
2504 :
2505 28 : class DeserializeFromTransfer : public ValueDeserializer::Delegate {
2506 : public:
2507 : DeserializeFromTransfer(
2508 : std::vector<WasmModuleObject::TransferrableModule>* modules)
2509 14 : : modules_(modules) {}
2510 :
2511 4 : MaybeLocal<WasmModuleObject> GetWasmModuleFromId(Isolate* isolate,
2512 : uint32_t id) override {
2513 : return WasmModuleObject::FromTransferrableModule(isolate,
2514 8 : modules_->at(id));
2515 : }
2516 :
2517 : private:
2518 : std::vector<WasmModuleObject::TransferrableModule>* modules_;
2519 : };
2520 :
2521 19 : ValueSerializer::Delegate* GetSerializerDelegate() override {
2522 19 : return current_serializer_delegate_;
2523 : }
2524 :
2525 12 : ValueDeserializer::Delegate* GetDeserializerDelegate() override {
2526 12 : return current_deserializer_delegate_;
2527 : }
2528 :
2529 12 : Local<WasmModuleObject> MakeWasm() {
2530 : Context::Scope scope(serialization_context());
2531 12 : return WasmModuleObject::DeserializeOrCompile(
2532 : isolate(), {nullptr, 0},
2533 12 : {kIncrementerWasm, sizeof(kIncrementerWasm)})
2534 12 : .ToLocalChecked();
2535 : }
2536 :
2537 2 : void ExpectPass() {
2538 4 : Local<Value> value = RoundTripTest(MakeWasm());
2539 : Context::Scope scope(deserialization_context());
2540 4 : ASSERT_TRUE(value->IsWebAssemblyCompiledModule());
2541 : ExpectScriptTrue(
2542 2 : "new WebAssembly.Instance(result).exports.increment(8) === 9");
2543 : }
2544 :
2545 3 : void ExpectFail() {
2546 6 : const std::vector<uint8_t> data = EncodeTest(MakeWasm());
2547 3 : InvalidDecodeTest(data);
2548 3 : }
2549 :
2550 2 : Local<Value> GetComplexObjectWithDuplicate() {
2551 : Context::Scope scope(serialization_context());
2552 2 : Local<Value> wasm_module = MakeWasm();
2553 : serialization_context()
2554 4 : ->Global()
2555 2 : ->CreateDataProperty(serialization_context(),
2556 4 : StringFromUtf8("wasm_module"), wasm_module)
2557 : .FromMaybe(false);
2558 : Local<Script> script =
2559 2 : Script::Compile(
2560 : serialization_context(),
2561 2 : StringFromUtf8("({mod1: wasm_module, num: 2, mod2: wasm_module})"))
2562 : .ToLocalChecked();
2563 4 : return script->Run(serialization_context()).ToLocalChecked();
2564 : }
2565 :
2566 4 : void VerifyComplexObject(Local<Value> value) {
2567 8 : ASSERT_TRUE(value->IsObject());
2568 4 : ExpectScriptTrue("result.mod1 instanceof WebAssembly.Module");
2569 4 : ExpectScriptTrue("result.mod2 instanceof WebAssembly.Module");
2570 4 : ExpectScriptTrue("result.num === 2");
2571 : }
2572 :
2573 2 : Local<Value> GetComplexObjectWithMany() {
2574 : Context::Scope scope(serialization_context());
2575 2 : Local<Value> wasm_module1 = MakeWasm();
2576 2 : Local<Value> wasm_module2 = MakeWasm();
2577 : serialization_context()
2578 4 : ->Global()
2579 2 : ->CreateDataProperty(serialization_context(),
2580 4 : StringFromUtf8("wasm_module1"), wasm_module1)
2581 : .FromMaybe(false);
2582 : serialization_context()
2583 4 : ->Global()
2584 2 : ->CreateDataProperty(serialization_context(),
2585 4 : StringFromUtf8("wasm_module2"), wasm_module2)
2586 : .FromMaybe(false);
2587 : Local<Script> script =
2588 2 : Script::Compile(
2589 : serialization_context(),
2590 : StringFromUtf8(
2591 2 : "({mod1: wasm_module1, num: 2, mod2: wasm_module2})"))
2592 : .ToLocalChecked();
2593 4 : return script->Run(serialization_context()).ToLocalChecked();
2594 : }
2595 :
2596 : private:
2597 : static bool g_saved_flag;
2598 : std::vector<WasmModuleObject::TransferrableModule> transfer_modules_;
2599 : SerializeToTransfer serialize_delegate_;
2600 : DeserializeFromTransfer deserialize_delegate_;
2601 : ValueSerializer::Delegate* current_serializer_delegate_ = nullptr;
2602 : ValueDeserializer::Delegate* current_deserializer_delegate_ = nullptr;
2603 : ThrowingSerializer throwing_serializer_;
2604 : ValueDeserializer::Delegate default_deserializer_;
2605 : };
2606 :
2607 : bool ValueSerializerTestWithWasm::g_saved_flag = false;
2608 : const char* ValueSerializerTestWithWasm::kUnsupportedSerialization =
2609 : "Wasm Serialization Not Supported";
2610 :
2611 : // The default implementation of the serialization
2612 : // delegate throws when trying to serialize wasm. The
2613 : // embedder must decide serialization policy.
2614 15443 : TEST_F(ValueSerializerTestWithWasm, DefaultSerializationDelegate) {
2615 : EnableThrowingSerializer();
2616 2 : Local<Message> message = InvalidEncodeTest(MakeWasm());
2617 2 : size_t msg_len = static_cast<size_t>(message->Get()->Length());
2618 1 : std::unique_ptr<char[]> buff(new char[msg_len + 1]);
2619 2 : message->Get()->WriteOneByte(isolate(),
2620 1 : reinterpret_cast<uint8_t*>(buff.get()));
2621 : // the message ends with the custom error string
2622 1 : size_t custom_msg_len = strlen(kUnsupportedSerialization);
2623 1 : ASSERT_GE(msg_len, custom_msg_len);
2624 1 : size_t start_pos = msg_len - custom_msg_len;
2625 2 : ASSERT_EQ(strcmp(&buff.get()[start_pos], kUnsupportedSerialization), 0);
2626 : }
2627 :
2628 : // The default deserializer throws if wasm transfer is attempted
2629 15443 : TEST_F(ValueSerializerTestWithWasm, DefaultDeserializationDelegate) {
2630 : EnableTransferSerialization();
2631 : EnableDefaultDeserializer();
2632 1 : ExpectFail();
2633 1 : }
2634 :
2635 : // We only want to allow deserialization through
2636 : // transferred modules - which requres both serializer
2637 : // and deserializer to understand that - or through
2638 : // explicitly allowing inlined data, which requires
2639 : // deserializer opt-in (we default the serializer to
2640 : // inlined data because we don't trust that data on the
2641 : // receiving end anyway).
2642 :
2643 15443 : TEST_F(ValueSerializerTestWithWasm, RoundtripWasmTransfer) {
2644 : EnableTransferSerialization();
2645 : EnableTransferDeserialization();
2646 1 : ExpectPass();
2647 1 : }
2648 :
2649 15443 : TEST_F(ValueSerializerTestWithWasm, RountripWasmInline) {
2650 : SetExpectInlineWasm(true);
2651 1 : ExpectPass();
2652 1 : }
2653 :
2654 15443 : TEST_F(ValueSerializerTestWithWasm, CannotDeserializeWasmInlineData) {
2655 1 : ExpectFail();
2656 1 : }
2657 :
2658 15443 : TEST_F(ValueSerializerTestWithWasm, CannotTransferWasmWhenExpectingInline) {
2659 : EnableTransferSerialization();
2660 : SetExpectInlineWasm(true);
2661 1 : ExpectFail();
2662 1 : }
2663 :
2664 15443 : TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateTransfer) {
2665 : EnableTransferSerialization();
2666 : EnableTransferDeserialization();
2667 1 : Local<Value> value = RoundTripTest(GetComplexObjectWithDuplicate());
2668 1 : VerifyComplexObject(value);
2669 1 : ExpectScriptTrue("result.mod1 === result.mod2");
2670 1 : }
2671 :
2672 15443 : TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateInline) {
2673 : SetExpectInlineWasm(true);
2674 1 : Local<Value> value = RoundTripTest(GetComplexObjectWithDuplicate());
2675 1 : VerifyComplexObject(value);
2676 1 : ExpectScriptTrue("result.mod1 === result.mod2");
2677 1 : }
2678 :
2679 15443 : TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyTransfer) {
2680 : EnableTransferSerialization();
2681 : EnableTransferDeserialization();
2682 1 : Local<Value> value = RoundTripTest(GetComplexObjectWithMany());
2683 1 : VerifyComplexObject(value);
2684 1 : ExpectScriptTrue("result.mod1 != result.mod2");
2685 1 : }
2686 :
2687 15443 : TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyInline) {
2688 : SetExpectInlineWasm(true);
2689 1 : Local<Value> value = RoundTripTest(GetComplexObjectWithMany());
2690 1 : VerifyComplexObject(value);
2691 1 : ExpectScriptTrue("result.mod1 != result.mod2");
2692 1 : }
2693 :
2694 : // As produced around Chrome 56.
2695 : const unsigned char kSerializedIncrementerWasm[] = {
2696 : 0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x2D, 0x00, 0x61, 0x73, 0x6D, 0x0D,
2697 : 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03,
2698 : 0x02, 0x01, 0x00, 0x07, 0x0D, 0x01, 0x09, 0x69, 0x6E, 0x63, 0x72, 0x65,
2699 : 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0x20,
2700 : 0x00, 0x41, 0x01, 0x6A, 0xF8, 0x04, 0xA1, 0x06, 0xDE, 0xC0, 0xC6, 0x44,
2701 : 0x3C, 0x29, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x02, 0x00, 0x00, 0x81, 0x4E,
2702 : 0xCE, 0x7C, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x30, 0x02,
2703 : 0x00, 0x00, 0xB0, 0x25, 0x30, 0xE3, 0xF2, 0xDB, 0x2E, 0x48, 0x00, 0x00,
2704 : 0x00, 0x80, 0xE8, 0x00, 0x00, 0x80, 0xE0, 0x01, 0x00, 0x80, 0x00, 0x00,
2705 : 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x07, 0x08, 0x00, 0x00, 0x09, 0x04,
2706 : 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3C, 0x8C, 0xC0, 0x00, 0x00,
2707 : 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x10, 0x8C, 0xC0, 0x00, 0x00,
2708 : 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x70, 0x94, 0x01, 0x0C, 0x8B,
2709 : 0xC1, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0xDC, 0x00,
2710 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x01, 0x10, 0x8C, 0xC0, 0x00, 0x00,
2711 : 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x84, 0xC0, 0x00, 0x00, 0x00, 0x00,
2712 : 0x00, 0x00, 0x00, 0x00, 0x05, 0x7D, 0x01, 0x1A, 0xE1, 0x02, 0x00, 0x00,
2713 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x88, 0x42, 0x32, 0x03,
2714 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00,
2715 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x04, 0x00,
2716 : 0x00, 0x02, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
2717 : 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x49, 0x3B, 0xA5, 0x60, 0x0C, 0x00,
2718 : 0x00, 0x0F, 0x86, 0x04, 0x00, 0x00, 0x00, 0x83, 0xC0, 0x01, 0xC3, 0x55,
2719 : 0x48, 0x89, 0xE5, 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
2720 : 0x00, 0x41, 0x52, 0x48, 0x83, 0xEC, 0x08, 0x48, 0x89, 0x45, 0xF0, 0x48,
2721 : 0xBB, 0xB0, 0x67, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xC0, 0x48,
2722 : 0xBE, 0xE1, 0x57, 0x81, 0x85, 0xF6, 0x14, 0x00, 0x00, 0xE8, 0xFC, 0x3C,
2723 : 0xEA, 0xFF, 0x48, 0x8B, 0x45, 0xF0, 0x48, 0x8B, 0xE5, 0x5D, 0xEB, 0xBF,
2724 : 0x66, 0x90, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x44, 0x00,
2725 : 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
2726 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2727 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2728 : 0x00, 0x00, 0x0F, 0x20, 0x84, 0x0F, 0x7D, 0x01, 0x0D, 0x00, 0x0F, 0x04,
2729 : 0x6D, 0x08, 0x0F, 0xF0, 0x02, 0x80, 0x94, 0x01, 0x0C, 0x8B, 0xC1, 0x00,
2730 : 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xED, 0xA9, 0x2D, 0x00, 0x00,
2731 : 0x00, 0x00, 0x00, 0x9E, 0xE0, 0x38, 0x1A, 0x61, 0x03, 0x00, 0x00, 0x00,
2732 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x23, 0x88, 0x42, 0x32, 0x03, 0x00,
2733 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00,
2734 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
2735 : 0x02, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
2736 : 0xFF, 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xE5, 0x56, 0x57, 0x48,
2737 : 0x8B, 0x45, 0x10, 0xE8, 0x11, 0xED, 0xED, 0xFF, 0xA8, 0x01, 0x0F, 0x85,
2738 : 0x2D, 0x00, 0x00, 0x00, 0x48, 0xC1, 0xE8, 0x20, 0xC5, 0xF9, 0x57, 0xC0,
2739 : 0xC5, 0xFB, 0x2A, 0xC0, 0xC4, 0xE1, 0xFB, 0x2C, 0xC0, 0x48, 0x83, 0xF8,
2740 : 0x01, 0x0F, 0x80, 0x34, 0x00, 0x00, 0x00, 0x8B, 0xC0, 0xE8, 0x27, 0xFE,
2741 : 0xFF, 0xFF, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x8B, 0xE5, 0x5D, 0xC2, 0x10,
2742 : 0x00, 0x49, 0x39, 0x45, 0xA0, 0x0F, 0x84, 0x07, 0x00, 0x00, 0x00, 0xC5,
2743 : 0xFB, 0x10, 0x40, 0x07, 0xEB, 0xCE, 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00,
2744 : 0x00, 0x00, 0xF8, 0x7F, 0xC4, 0xC1, 0xF9, 0x6E, 0xC2, 0xEB, 0xBD, 0x48,
2745 : 0x83, 0xEC, 0x08, 0xC5, 0xFB, 0x11, 0x04, 0x24, 0xE8, 0xCC, 0xFE, 0xFF,
2746 : 0xFF, 0x48, 0x83, 0xC4, 0x08, 0xEB, 0xB8, 0x66, 0x90, 0x02, 0x00, 0x00,
2747 : 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
2748 : 0x0F, 0x39, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00,
2749 : 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x20, 0x84,
2750 : 0x0F, 0xCC, 0x6E, 0x7D, 0x01, 0x72, 0x98, 0x00, 0x0F, 0xDC, 0x6D, 0x0C,
2751 : 0x0F, 0xB0, 0x84, 0x0D, 0x04, 0x84, 0xE3, 0xC0, 0x00, 0x00, 0x00, 0x00,
2752 : 0x00, 0x00, 0x00, 0x00, 0x84, 0xE0, 0x84, 0x84, 0x18, 0x2F, 0x2F, 0x2F,
2753 : 0x2F, 0x2F};
2754 :
2755 15443 : TEST_F(ValueSerializerTestWithWasm, DecodeWasmModule) {
2756 : if ((true)) return; // TODO(mtrofin): fix this test
2757 : std::vector<uint8_t> raw(
2758 : kSerializedIncrementerWasm,
2759 : kSerializedIncrementerWasm + sizeof(kSerializedIncrementerWasm));
2760 : Local<Value> value = DecodeTest(raw);
2761 : ASSERT_TRUE(value->IsWebAssemblyCompiledModule());
2762 : ExpectScriptTrue(
2763 : "new WebAssembly.Instance(result).exports.increment(8) === 9");
2764 : }
2765 :
2766 : // As above, but with empty compiled data. Should work due to fallback to wire
2767 : // data.
2768 : const unsigned char kSerializedIncrementerWasmWithInvalidCompiledData[] = {
2769 : 0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x2D, 0x00, 0x61, 0x73, 0x6D,
2770 : 0x0D, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F, 0x01,
2771 : 0x7F, 0x03, 0x02, 0x01, 0x00, 0x07, 0x0D, 0x01, 0x09, 0x69, 0x6E,
2772 : 0x63, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x00, 0x0A, 0x08,
2773 : 0x01, 0x06, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6A, 0x00};
2774 :
2775 15443 : TEST_F(ValueSerializerTestWithWasm, DecodeWasmModuleWithInvalidCompiledData) {
2776 : if ((true)) return; // TODO(titzer): regenerate this test
2777 : std::vector<uint8_t> raw(
2778 : kSerializedIncrementerWasmWithInvalidCompiledData,
2779 : kSerializedIncrementerWasmWithInvalidCompiledData +
2780 : sizeof(kSerializedIncrementerWasmWithInvalidCompiledData));
2781 : Local<Value> value = DecodeTest(raw);
2782 : ASSERT_TRUE(value->IsWebAssemblyCompiledModule());
2783 : ExpectScriptTrue(
2784 : "new WebAssembly.Instance(result).exports.increment(8) === 9");
2785 : }
2786 :
2787 : // As above, but also with empty wire data. Should fail.
2788 : const unsigned char kSerializedIncrementerWasmInvalid[] = {
2789 : 0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x00, 0x00};
2790 :
2791 15443 : TEST_F(ValueSerializerTestWithWasm,
2792 : DecodeWasmModuleWithInvalidCompiledAndWireData) {
2793 : std::vector<uint8_t> raw(kSerializedIncrementerWasmInvalid,
2794 : kSerializedIncrementerWasmInvalid +
2795 : sizeof(kSerializedIncrementerWasmInvalid));
2796 1 : InvalidDecodeTest(raw);
2797 1 : }
2798 :
2799 15443 : TEST_F(ValueSerializerTestWithWasm, DecodeWasmModuleWithInvalidDataLength) {
2800 2 : InvalidDecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x7F, 0x00});
2801 2 : InvalidDecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x00, 0x7F});
2802 1 : }
2803 :
2804 4 : class ValueSerializerTestWithLimitedMemory : public ValueSerializerTest {
2805 : protected:
2806 : // GMock doesn't use the "override" keyword.
2807 : #if __clang__
2808 : #pragma clang diagnostic push
2809 : #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2810 : #endif
2811 :
2812 : class SerializerDelegate : public ValueSerializer::Delegate {
2813 : public:
2814 : explicit SerializerDelegate(ValueSerializerTestWithLimitedMemory* test)
2815 2 : : test_(test) {}
2816 :
2817 4 : ~SerializerDelegate() { EXPECT_EQ(nullptr, last_buffer_); }
2818 :
2819 3 : void SetMemoryLimit(size_t limit) { memory_limit_ = limit; }
2820 :
2821 6 : void* ReallocateBufferMemory(void* old_buffer, size_t size,
2822 : size_t* actual_size) override {
2823 12 : EXPECT_EQ(old_buffer, last_buffer_);
2824 6 : if (size > memory_limit_) return nullptr;
2825 4 : *actual_size = size;
2826 4 : last_buffer_ = realloc(old_buffer, size);
2827 4 : return last_buffer_;
2828 : }
2829 :
2830 3 : void FreeBufferMemory(void* buffer) override {
2831 6 : EXPECT_EQ(buffer, last_buffer_);
2832 3 : last_buffer_ = nullptr;
2833 3 : free(buffer);
2834 3 : }
2835 :
2836 2 : void ThrowDataCloneError(Local<String> message) override {
2837 4 : test_->isolate()->ThrowException(Exception::Error(message));
2838 2 : }
2839 :
2840 7 : MOCK_METHOD2(WriteHostObject,
2841 : Maybe<bool>(Isolate* isolate, Local<Object> object));
2842 :
2843 : private:
2844 : ValueSerializerTestWithLimitedMemory* test_;
2845 : void* last_buffer_ = nullptr;
2846 : size_t memory_limit_ = 0;
2847 : };
2848 :
2849 : #if __clang__
2850 : #pragma clang diagnostic pop
2851 : #endif
2852 :
2853 4 : ValueSerializer::Delegate* GetSerializerDelegate() override {
2854 4 : return &serializer_delegate_;
2855 : }
2856 :
2857 3 : void BeforeEncode(ValueSerializer* serializer) override {
2858 3 : serializer_ = serializer;
2859 3 : }
2860 :
2861 : SerializerDelegate serializer_delegate_{this};
2862 : ValueSerializer* serializer_ = nullptr;
2863 : };
2864 :
2865 15443 : TEST_F(ValueSerializerTestWithLimitedMemory, FailIfNoMemoryInWriteHostObject) {
2866 5 : EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
2867 3 : .WillRepeatedly(Invoke([this](Isolate*, Local<Object>) {
2868 : static const char kDummyData[1024] = {};
2869 3 : serializer_->WriteRawBytes(&kDummyData, sizeof(kDummyData));
2870 : return Just(true);
2871 2 : }));
2872 :
2873 : // If there is enough memory, things work.
2874 : serializer_delegate_.SetMemoryLimit(2048);
2875 2 : EncodeTest("new ExampleHostObject()");
2876 :
2877 : // If not, we get a graceful failure, rather than silent misbehavior.
2878 : serializer_delegate_.SetMemoryLimit(1024);
2879 : InvalidEncodeTest("new ExampleHostObject()");
2880 :
2881 : // And we definitely don't continue to serialize other things.
2882 : serializer_delegate_.SetMemoryLimit(1024);
2883 1 : EvaluateScriptForInput("gotA = false");
2884 : InvalidEncodeTest("[new ExampleHostObject, {get a() { gotA = true; }}]");
2885 3 : EXPECT_TRUE(EvaluateScriptForInput("gotA")->IsFalse());
2886 1 : }
2887 :
2888 : } // namespace
2889 9264 : } // namespace v8
|