1/*
2 * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
28#include "SerializedScriptValue.h"
29
30#include "BlobRegistry.h"
31#include "CryptoKeyAES.h"
32#include "CryptoKeyEC.h"
33#include "CryptoKeyHMAC.h"
34#include "CryptoKeyRSA.h"
35#include "CryptoKeyRSAComponents.h"
36#include "CryptoKeyRaw.h"
37#include "IDBValue.h"
38#include "JSBlob.h"
39#include "JSCryptoKey.h"
40#include "JSDOMBinding.h"
41#include "JSDOMConvertBufferSource.h"
42#include "JSDOMGlobalObject.h"
43#include "JSDOMMatrix.h"
44#include "JSDOMPoint.h"
45#include "JSDOMQuad.h"
46#include "JSDOMRect.h"
47#include "JSFile.h"
48#include "JSFileList.h"
49#include "JSImageBitmap.h"
50#include "JSImageData.h"
51#include "JSMessagePort.h"
52#include "JSNavigator.h"
53#include "JSRTCCertificate.h"
54#include "ScriptExecutionContext.h"
55#include "ScriptState.h"
56#include "SharedBuffer.h"
57#include "WebCoreJSClientData.h"
58#include <JavaScriptCore/APICast.h>
59#include <JavaScriptCore/BooleanObject.h>
60#include <JavaScriptCore/CatchScope.h>
61#include <JavaScriptCore/DateInstance.h>
62#include <JavaScriptCore/Error.h>
63#include <JavaScriptCore/Exception.h>
64#include <JavaScriptCore/ExceptionHelpers.h>
65#include <JavaScriptCore/IterationKind.h>
66#include <JavaScriptCore/JSArrayBuffer.h>
67#include <JavaScriptCore/JSArrayBufferView.h>
68#include <JavaScriptCore/JSCInlines.h>
69#include <JavaScriptCore/JSDataView.h>
70#include <JavaScriptCore/JSMap.h>
71#include <JavaScriptCore/JSMapIterator.h>
72#include <JavaScriptCore/JSSet.h>
73#include <JavaScriptCore/JSSetIterator.h>
74#include <JavaScriptCore/JSTypedArrays.h>
75#include <JavaScriptCore/JSWebAssemblyModule.h>
76#include <JavaScriptCore/ObjectConstructor.h>
77#include <JavaScriptCore/PropertyNameArray.h>
78#include <JavaScriptCore/RegExp.h>
79#include <JavaScriptCore/RegExpObject.h>
80#include <JavaScriptCore/TypedArrayInlines.h>
81#include <JavaScriptCore/TypedArrays.h>
82#include <JavaScriptCore/WasmModule.h>
83#include <JavaScriptCore/YarrFlags.h>
84#include <limits>
85#include <wtf/CompletionHandler.h>
86#include <wtf/MainThread.h>
87#include <wtf/RunLoop.h>
88#include <wtf/Vector.h>
89
90#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
91#define ASSUME_LITTLE_ENDIAN 0
92#else
93#define ASSUME_LITTLE_ENDIAN 1
94#endif
95
96namespace WebCore {
97using namespace JSC;
98
99static const unsigned maximumFilterRecursion = 40000;
100
101enum class SerializationReturnCode {
102 SuccessfullyCompleted,
103 StackOverflowError,
104 InterruptedExecutionError,
105 ValidationError,
106 ExistingExceptionError,
107 DataCloneError,
108 UnspecifiedError
109};
110
111enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
112 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
113 MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue,
114 SetDataStartVisitEntry, SetDataEndVisitKey };
115
116// These can't be reordered, and any new types must be added to the end of the list
117// When making changes to these lists please cover your new type(s) in the API test "IndexedDB.StructuredCloneBackwardCompatibility"
118enum SerializationTag {
119 ArrayTag = 1,
120 ObjectTag = 2,
121 UndefinedTag = 3,
122 NullTag = 4,
123 IntTag = 5,
124 ZeroTag = 6,
125 OneTag = 7,
126 FalseTag = 8,
127 TrueTag = 9,
128 DoubleTag = 10,
129 DateTag = 11,
130 FileTag = 12,
131 FileListTag = 13,
132 ImageDataTag = 14,
133 BlobTag = 15,
134 StringTag = 16,
135 EmptyStringTag = 17,
136 RegExpTag = 18,
137 ObjectReferenceTag = 19,
138 MessagePortReferenceTag = 20,
139 ArrayBufferTag = 21,
140 ArrayBufferViewTag = 22,
141 ArrayBufferTransferTag = 23,
142 TrueObjectTag = 24,
143 FalseObjectTag = 25,
144 StringObjectTag = 26,
145 EmptyStringObjectTag = 27,
146 NumberObjectTag = 28,
147 SetObjectTag = 29,
148 MapObjectTag = 30,
149 NonMapPropertiesTag = 31,
150 NonSetPropertiesTag = 32,
151#if ENABLE(WEB_CRYPTO)
152 CryptoKeyTag = 33,
153#endif
154 SharedArrayBufferTag = 34,
155#if ENABLE(WEBASSEMBLY)
156 WasmModuleTag = 35,
157#endif
158 DOMPointReadOnlyTag = 36,
159 DOMPointTag = 37,
160 DOMRectReadOnlyTag = 38,
161 DOMRectTag = 39,
162 DOMMatrixReadOnlyTag = 40,
163 DOMMatrixTag = 41,
164 DOMQuadTag = 42,
165 ImageBitmapTransferTag = 43,
166#if ENABLE(WEB_RTC)
167 RTCCertificateTag = 44,
168#endif
169 ErrorTag = 255
170};
171
172enum ArrayBufferViewSubtag {
173 DataViewTag = 0,
174 Int8ArrayTag = 1,
175 Uint8ArrayTag = 2,
176 Uint8ClampedArrayTag = 3,
177 Int16ArrayTag = 4,
178 Uint16ArrayTag = 5,
179 Int32ArrayTag = 6,
180 Uint32ArrayTag = 7,
181 Float32ArrayTag = 8,
182 Float64ArrayTag = 9
183};
184
185static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
186{
187 switch (tag) {
188 case DataViewTag:
189 case Int8ArrayTag:
190 case Uint8ArrayTag:
191 case Uint8ClampedArrayTag:
192 return 1;
193 case Int16ArrayTag:
194 case Uint16ArrayTag:
195 return 2;
196 case Int32ArrayTag:
197 case Uint32ArrayTag:
198 case Float32ArrayTag:
199 return 4;
200 case Float64ArrayTag:
201 return 8;
202 default:
203 return 0;
204 }
205
206}
207
208#if ENABLE(WEB_CRYPTO)
209
210const uint32_t currentKeyFormatVersion = 1;
211
212enum class CryptoKeyClassSubtag {
213 HMAC = 0,
214 AES = 1,
215 RSA = 2,
216 EC = 3,
217 Raw = 4,
218};
219const uint8_t cryptoKeyClassSubtagMaximumValue = 4;
220
221enum class CryptoKeyAsymmetricTypeSubtag {
222 Public = 0,
223 Private = 1
224};
225const uint8_t cryptoKeyAsymmetricTypeSubtagMaximumValue = 1;
226
227enum class CryptoKeyUsageTag {
228 Encrypt = 0,
229 Decrypt = 1,
230 Sign = 2,
231 Verify = 3,
232 DeriveKey = 4,
233 DeriveBits = 5,
234 WrapKey = 6,
235 UnwrapKey = 7
236};
237const uint8_t cryptoKeyUsageTagMaximumValue = 7;
238
239enum class CryptoAlgorithmIdentifierTag {
240 RSAES_PKCS1_v1_5 = 0,
241 RSASSA_PKCS1_v1_5 = 1,
242 RSA_PSS = 2,
243 RSA_OAEP = 3,
244 ECDSA = 4,
245 ECDH = 5,
246 AES_CTR = 6,
247 AES_CBC = 7,
248 AES_GCM = 9,
249 AES_CFB = 10,
250 AES_KW = 11,
251 HMAC = 12,
252 SHA_1 = 14,
253 SHA_224 = 15,
254 SHA_256 = 16,
255 SHA_384 = 17,
256 SHA_512 = 18,
257 HKDF = 20,
258 PBKDF2 = 21,
259};
260const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21;
261
262static unsigned countUsages(CryptoKeyUsageBitmap usages)
263{
264 // Fast bit count algorithm for sparse bit maps.
265 unsigned count = 0;
266 while (usages) {
267 usages = usages & (usages - 1);
268 ++count;
269 }
270 return count;
271}
272
273#endif
274
275/* CurrentVersion tracks the serialization version so that persistent stores
276 * are able to correctly bail out in the case of encountering newer formats.
277 *
278 * Initial version was 1.
279 * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
280 * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
281 * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
282 * Version 4. added support for serializing non-index properties of arrays.
283 * Version 5. added support for Map and Set types.
284 * Version 6. added support for 8-bit strings.
285 * Version 7. added support for File's lastModified attribute.
286 */
287static const unsigned CurrentVersion = 7;
288static const unsigned TerminatorTag = 0xFFFFFFFF;
289static const unsigned StringPoolTag = 0xFFFFFFFE;
290static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
291
292// The high bit of a StringData's length determines the character size.
293static const unsigned StringDataIs8BitFlag = 0x80000000;
294
295/*
296 * Object serialization is performed according to the following grammar, all tags
297 * are recorded as a single uint8_t.
298 *
299 * IndexType (used for the object pool and StringData's constant pool) is the
300 * minimum sized unsigned integer type required to represent the maximum index
301 * in the constant pool.
302 *
303 * SerializedValue :- <CurrentVersion:uint32_t> Value
304 * Value :- Array | Object | Map | Set | Terminal
305 *
306 * Array :-
307 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
308 *
309 * Object :-
310 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
311 *
312 * Map :- MapObjectTag MapData
313 *
314 * Set :- SetObjectTag SetData
315 *
316 * MapData :- (<key:Value><value:Value>)* NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
317 * SetData :- (<key:Value>)* NonSetPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
318 *
319 * Terminal :-
320 * UndefinedTag
321 * | NullTag
322 * | IntTag <value:int32_t>
323 * | ZeroTag
324 * | OneTag
325 * | FalseTag
326 * | TrueTag
327 * | FalseObjectTag
328 * | TrueObjectTag
329 * | DoubleTag <value:double>
330 * | NumberObjectTag <value:double>
331 * | DateTag <value:double>
332 * | String
333 * | EmptyStringTag
334 * | EmptyStringObjectTag
335 * | File
336 * | FileList
337 * | ImageData
338 * | Blob
339 * | ObjectReference
340 * | MessagePortReferenceTag <value:uint32_t>
341 * | ArrayBuffer
342 * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference)
343 * | ArrayBufferTransferTag <value:uint32_t>
344 * | CryptoKeyTag <wrappedKeyLength:uint32_t> <factor:byte{wrappedKeyLength}>
345 * | DOMPoint
346 * | DOMRect
347 * | DOMMatrix
348 * | DOMQuad
349 * | ImageBitmapTransferTag <value:uint32_t>
350 * | RTCCertificateTag
351 *
352 * Inside certificate, data is serialized in this format as per spec:
353 *
354 * <expires:double> <certificate:StringData> <origin:StringData> <keyingMaterial:StringData>
355 * We also add fingerprints to make sure we expose to JavaScript the same information.
356 *
357 * Inside wrapped crypto key, data is serialized in this format:
358 *
359 * <keyFormatVersion:uint32_t> <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA)
360 *
361 * String :-
362 * EmptyStringTag
363 * StringTag StringData
364 *
365 * StringObject:
366 * EmptyStringObjectTag
367 * StringObjectTag StringData
368 *
369 * StringData :-
370 * StringPoolTag <cpIndex:IndexType>
371 * (not (TerminatorTag | StringPoolTag))<is8Bit:uint32_t:1><length:uint32_t:31><characters:CharType{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
372 *
373 * File :-
374 * FileTag FileData
375 *
376 * FileData :-
377 * <path:StringData> <url:StringData> <type:StringData> <name:StringData> <lastModified:double>
378 *
379 * FileList :-
380 * FileListTag <length:uint32_t>(<file:FileData>){length}
381 *
382 * ImageData :-
383 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
384 *
385 * Blob :-
386 * BlobTag <url:StringData><type:StringData><size:long long>
387 *
388 * RegExp :-
389 * RegExpTag <pattern:StringData><flags:StringData>
390 *
391 * ObjectReference :-
392 * ObjectReferenceTag <opIndex:IndexType>
393 *
394 * ArrayBuffer :-
395 * ArrayBufferTag <length:uint32_t> <contents:byte{length}>
396 *
397 * CryptoKeyHMAC :-
398 * <keySize:uint32_t> <keyData:byte{keySize}> CryptoAlgorithmIdentifierTag // Algorithm tag inner hash function.
399 *
400 * CryptoKeyAES :-
401 * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
402 *
403 * CryptoKeyRSA :-
404 * CryptoAlgorithmIdentifierTag <isRestrictedToHash:int32_t> CryptoAlgorithmIdentifierTag? CryptoKeyAsymmetricTypeSubtag CryptoKeyRSAPublicComponents CryptoKeyRSAPrivateComponents?
405 *
406 * CryptoKeyRSAPublicComponents :-
407 * <modulusSize:uint32_t> <modulus:byte{modulusSize}> <exponentSize:uint32_t> <exponent:byte{exponentSize}>
408 *
409 * CryptoKeyRSAPrivateComponents :-
410 * <privateExponentSize:uint32_t> <privateExponent:byte{privateExponentSize}> <primeCount:uint32_t> FirstPrimeInfo? PrimeInfo{primeCount - 1}
411 *
412 * // CRT data could be computed from prime factors. It is only serialized to reuse a code path that's needed for JWK.
413 * FirstPrimeInfo :-
414 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}>
415 *
416 * PrimeInfo :-
417 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}>
418 *
419 * CryptoKeyEC :-
420 * CryptoAlgorithmIdentifierTag <namedCurve:StringData> CryptoKeyAsymmetricTypeSubtag <keySize:uint32_t> <keyData:byte{keySize}>
421 *
422 * CryptoKeyRaw :-
423 * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
424 *
425 * DOMPoint :-
426 * DOMPointReadOnlyTag DOMPointData
427 * | DOMPointTag DOMPointData
428 *
429 * DOMPointData :-
430 * <x:double> <y:double> <z:double> <w:double>
431 *
432 * DOMRect :-
433 * DOMRectReadOnlyTag DOMRectData
434 * | DOMRectTag DOMRectData
435 *
436 * DOMRectData :-
437 * <x:double> <y:double> <width:double> <height:double>
438 *
439 * DOMMatrix :-
440 * DOMMatrixReadOnlyTag DOMMatrixData
441 * | DOMMatrixTag DOMMatrixData
442 *
443 * DOMMatrixData :-
444 * <is2D:uint8_t:true> <m11:double> <m12:double> <m21:double> <m22:double> <m41:double> <m42:double>
445 * | <is2D:uint8_t:false> <m11:double> <m12:double> <m13:double> <m14:double> <m21:double> <m22:double> <m23:double> <m24:double> <m31:double> <m32:double> <m33:double> <m34:double> <m41:double> <m42:double> <m43:double> <m44:double>
446 *
447 * DOMQuad :-
448 * DOMQuadTag DOMQuadData
449 *
450 * DOMQuadData :-
451 * <p1:DOMPointData> <p2:DOMPointData> <p3:DOMPointData> <p4:DOMPointData>
452 *
453 */
454
455using DeserializationResult = std::pair<JSC::JSValue, SerializationReturnCode>;
456
457class CloneBase {
458protected:
459 CloneBase(ExecState* exec)
460 : m_exec(exec)
461 , m_failed(false)
462 {
463 }
464
465 bool shouldTerminate()
466 {
467 VM& vm = m_exec->vm();
468 auto scope = DECLARE_THROW_SCOPE(vm);
469 return scope.exception();
470 }
471
472 void fail()
473 {
474 m_failed = true;
475 }
476
477 ExecState* m_exec;
478 bool m_failed;
479 MarkedArgumentBuffer m_gcBuffer;
480};
481
482#if ENABLE(WEB_CRYPTO)
483static bool wrapCryptoKey(ExecState* exec, const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey)
484{
485 ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
486 if (!scriptExecutionContext)
487 return false;
488 return scriptExecutionContext->wrapCryptoKey(key, wrappedKey);
489}
490
491static bool unwrapCryptoKey(ExecState* exec, const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key)
492{
493 ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
494 if (!scriptExecutionContext)
495 return false;
496 return scriptExecutionContext->unwrapCryptoKey(wrappedKey, key);
497}
498#endif
499
500#if ASSUME_LITTLE_ENDIAN
501template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
502{
503 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
504}
505#else
506template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
507{
508 for (unsigned i = 0; i < sizeof(T); i++) {
509 buffer.append(value & 0xFF);
510 value >>= 8;
511 }
512}
513#endif
514
515template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
516{
517 buffer.append(value);
518}
519
520template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
521{
522 if (length > std::numeric_limits<uint32_t>::max() / sizeof(T))
523 return false;
524
525#if ASSUME_LITTLE_ENDIAN
526 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
527#else
528 for (unsigned i = 0; i < length; i++) {
529 T value = values[i];
530 for (unsigned j = 0; j < sizeof(T); j++) {
531 buffer.append(static_cast<uint8_t>(value & 0xFF));
532 value >>= 8;
533 }
534 }
535#endif
536 return true;
537}
538
539template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8_t* values, uint32_t length)
540{
541 buffer.append(values, length);
542 return true;
543}
544
545class CloneSerializer : CloneBase {
546public:
547 static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, const Vector<RefPtr<ImageBitmap>>& imageBitmaps,
548#if ENABLE(WEBASSEMBLY)
549 WasmModuleArray& wasmModules,
550#endif
551 Vector<String>& blobURLs, const PAL::SessionID& sessionID, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
552 {
553 CloneSerializer serializer(exec, messagePorts, arrayBuffers, imageBitmaps,
554#if ENABLE(WEBASSEMBLY)
555 wasmModules,
556#endif
557 blobURLs, sessionID, out, context, sharedBuffers);
558 return serializer.serialize(value);
559 }
560
561 static bool serialize(StringView string, Vector<uint8_t>& out)
562 {
563 writeLittleEndian(out, CurrentVersion);
564 if (string.isEmpty()) {
565 writeLittleEndian<uint8_t>(out, EmptyStringTag);
566 return true;
567 }
568 writeLittleEndian<uint8_t>(out, StringTag);
569 if (string.is8Bit()) {
570 writeLittleEndian(out, string.length() | StringDataIs8BitFlag);
571 return writeLittleEndian(out, string.characters8(), string.length());
572 }
573 writeLittleEndian(out, string.length());
574 return writeLittleEndian(out, string.characters16(), string.length());
575 }
576
577private:
578 typedef HashMap<JSObject*, uint32_t> ObjectPool;
579
580 CloneSerializer(ExecState* exec, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, const Vector<RefPtr<ImageBitmap>>& imageBitmaps,
581#if ENABLE(WEBASSEMBLY)
582 WasmModuleArray& wasmModules,
583#endif
584 Vector<String>& blobURLs, const PAL::SessionID& sessionID, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
585 : CloneBase(exec)
586 , m_buffer(out)
587 , m_blobURLs(blobURLs)
588 , m_sessionID(sessionID)
589 , m_emptyIdentifier(Identifier::fromString(exec, emptyString()))
590 , m_context(context)
591 , m_sharedBuffers(sharedBuffers)
592#if ENABLE(WEBASSEMBLY)
593 , m_wasmModules(wasmModules)
594#endif
595 {
596 write(CurrentVersion);
597 fillTransferMap(messagePorts, m_transferredMessagePorts);
598 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
599 fillTransferMap(imageBitmaps, m_transferredImageBitmaps);
600 }
601
602 template <class T>
603 void fillTransferMap(const Vector<RefPtr<T>>& input, ObjectPool& result)
604 {
605 if (input.isEmpty())
606 return;
607 JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
608 for (size_t i = 0; i < input.size(); i++) {
609 JSC::JSValue value = toJS(m_exec, globalObject, input[i].get());
610 JSC::JSObject* obj = value.getObject();
611 if (obj && !result.contains(obj))
612 result.add(obj, i);
613 }
614 }
615
616 SerializationReturnCode serialize(JSValue in);
617
618 bool isArray(VM& vm, JSValue value)
619 {
620 if (!value.isObject())
621 return false;
622 JSObject* object = asObject(value);
623 return object->inherits<JSArray>(vm);
624 }
625
626 bool isMap(VM& vm, JSValue value)
627 {
628 if (!value.isObject())
629 return false;
630 JSObject* object = asObject(value);
631 return object->inherits<JSMap>(vm);
632 }
633 bool isSet(VM& vm, JSValue value)
634 {
635 if (!value.isObject())
636 return false;
637 JSObject* object = asObject(value);
638 return object->inherits<JSSet>(vm);
639 }
640
641 bool checkForDuplicate(JSObject* object)
642 {
643 // Record object for graph reconstruction
644 ObjectPool::const_iterator found = m_objectPool.find(object);
645
646 // Handle duplicate references
647 if (found != m_objectPool.end()) {
648 write(ObjectReferenceTag);
649 ASSERT(found->value < m_objectPool.size());
650 writeObjectIndex(found->value);
651 return true;
652 }
653
654 return false;
655 }
656
657 void recordObject(JSObject* object)
658 {
659 m_objectPool.add(object, m_objectPool.size());
660 m_gcBuffer.appendWithCrashOnOverflow(object);
661 }
662
663 bool startObjectInternal(JSObject* object)
664 {
665 if (checkForDuplicate(object))
666 return false;
667 recordObject(object);
668 return true;
669 }
670
671 bool startObject(JSObject* object)
672 {
673 if (!startObjectInternal(object))
674 return false;
675 write(ObjectTag);
676 return true;
677 }
678
679 bool startArray(JSArray* array)
680 {
681 if (!startObjectInternal(array))
682 return false;
683
684 unsigned length = array->length();
685 write(ArrayTag);
686 write(length);
687 return true;
688 }
689
690 bool startSet(JSSet* set)
691 {
692 if (!startObjectInternal(set))
693 return false;
694
695 write(SetObjectTag);
696 return true;
697 }
698
699 bool startMap(JSMap* map)
700 {
701 if (!startObjectInternal(map))
702 return false;
703
704 write(MapObjectTag);
705 return true;
706 }
707
708 void endObject()
709 {
710 write(TerminatorTag);
711 }
712
713 JSValue getProperty(VM& vm, JSObject* object, const Identifier& propertyName)
714 {
715 PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
716 if (object->methodTable(vm)->getOwnPropertySlot(object, m_exec, propertyName, slot))
717 return slot.getValue(m_exec, propertyName);
718 return JSValue();
719 }
720
721 void dumpImmediate(JSValue value)
722 {
723 if (value.isNull())
724 write(NullTag);
725 else if (value.isUndefined())
726 write(UndefinedTag);
727 else if (value.isNumber()) {
728 if (value.isInt32()) {
729 if (!value.asInt32())
730 write(ZeroTag);
731 else if (value.asInt32() == 1)
732 write(OneTag);
733 else {
734 write(IntTag);
735 write(static_cast<uint32_t>(value.asInt32()));
736 }
737 } else {
738 write(DoubleTag);
739 write(value.asDouble());
740 }
741 } else if (value.isBoolean()) {
742 if (value.isTrue())
743 write(TrueTag);
744 else
745 write(FalseTag);
746 }
747 }
748
749 void dumpString(const String& string)
750 {
751 if (string.isEmpty())
752 write(EmptyStringTag);
753 else {
754 write(StringTag);
755 write(string);
756 }
757 }
758
759 void dumpStringObject(const String& string)
760 {
761 if (string.isEmpty())
762 write(EmptyStringObjectTag);
763 else {
764 write(StringObjectTag);
765 write(string);
766 }
767 }
768
769 JSC::JSValue toJSArrayBuffer(ArrayBuffer& arrayBuffer)
770 {
771 auto& vm = m_exec->vm();
772 auto* globalObject = m_exec->lexicalGlobalObject();
773 if (globalObject->inherits<JSDOMGlobalObject>(vm))
774 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(globalObject), &arrayBuffer);
775
776 if (auto* buffer = arrayBuffer.m_wrapper.get())
777 return buffer;
778
779 return JSC::JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(arrayBuffer.sharingMode()), &arrayBuffer);
780 }
781
782 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
783 {
784 VM& vm = m_exec->vm();
785 write(ArrayBufferViewTag);
786 if (obj->inherits<JSDataView>(vm))
787 write(DataViewTag);
788 else if (obj->inherits<JSUint8ClampedArray>(vm))
789 write(Uint8ClampedArrayTag);
790 else if (obj->inherits<JSInt8Array>(vm))
791 write(Int8ArrayTag);
792 else if (obj->inherits<JSUint8Array>(vm))
793 write(Uint8ArrayTag);
794 else if (obj->inherits<JSInt16Array>(vm))
795 write(Int16ArrayTag);
796 else if (obj->inherits<JSUint16Array>(vm))
797 write(Uint16ArrayTag);
798 else if (obj->inherits<JSInt32Array>(vm))
799 write(Int32ArrayTag);
800 else if (obj->inherits<JSUint32Array>(vm))
801 write(Uint32ArrayTag);
802 else if (obj->inherits<JSFloat32Array>(vm))
803 write(Float32ArrayTag);
804 else if (obj->inherits<JSFloat64Array>(vm))
805 write(Float64ArrayTag);
806 else
807 return false;
808
809 RefPtr<ArrayBufferView> arrayBufferView = toPossiblySharedArrayBufferView(vm, obj);
810 write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
811 write(static_cast<uint32_t>(arrayBufferView->byteLength()));
812 RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->possiblySharedBuffer();
813 if (!arrayBuffer) {
814 code = SerializationReturnCode::ValidationError;
815 return true;
816 }
817
818 return dumpIfTerminal(toJSArrayBuffer(*arrayBuffer), code);
819 }
820
821 void dumpDOMPoint(const DOMPointReadOnly& point)
822 {
823 write(point.x());
824 write(point.y());
825 write(point.z());
826 write(point.w());
827 }
828
829 void dumpDOMPoint(JSObject* obj)
830 {
831 VM& vm = m_exec->vm();
832 if (obj->inherits<JSDOMPoint>(vm))
833 write(DOMPointTag);
834 else
835 write(DOMPointReadOnlyTag);
836
837 dumpDOMPoint(jsCast<JSDOMPointReadOnly*>(obj)->wrapped());
838 }
839
840 void dumpDOMRect(JSObject* obj)
841 {
842 VM& vm = m_exec->vm();
843 if (obj->inherits<JSDOMRect>(vm))
844 write(DOMRectTag);
845 else
846 write(DOMRectReadOnlyTag);
847
848 auto& rect = jsCast<JSDOMRectReadOnly*>(obj)->wrapped();
849 write(rect.x());
850 write(rect.y());
851 write(rect.width());
852 write(rect.height());
853 }
854
855 void dumpDOMMatrix(JSObject* obj)
856 {
857 VM& vm = m_exec->vm();
858 if (obj->inherits<JSDOMMatrix>(vm))
859 write(DOMMatrixTag);
860 else
861 write(DOMMatrixReadOnlyTag);
862
863 auto& matrix = jsCast<JSDOMMatrixReadOnly*>(obj)->wrapped();
864 bool is2D = matrix.is2D();
865 write(static_cast<uint8_t>(is2D));
866 if (is2D) {
867 write(matrix.m11());
868 write(matrix.m12());
869 write(matrix.m21());
870 write(matrix.m22());
871 write(matrix.m41());
872 write(matrix.m42());
873 } else {
874 write(matrix.m11());
875 write(matrix.m12());
876 write(matrix.m13());
877 write(matrix.m14());
878 write(matrix.m21());
879 write(matrix.m22());
880 write(matrix.m23());
881 write(matrix.m24());
882 write(matrix.m31());
883 write(matrix.m32());
884 write(matrix.m33());
885 write(matrix.m34());
886 write(matrix.m41());
887 write(matrix.m42());
888 write(matrix.m43());
889 write(matrix.m44());
890 }
891 }
892
893 void dumpDOMQuad(JSObject* obj)
894 {
895 write(DOMQuadTag);
896
897 auto& quad = jsCast<JSDOMQuad*>(obj)->wrapped();
898 dumpDOMPoint(quad.p1());
899 dumpDOMPoint(quad.p2());
900 dumpDOMPoint(quad.p3());
901 dumpDOMPoint(quad.p4());
902 }
903
904 void dumpImageBitmap(JSObject* obj, SerializationReturnCode& code)
905 {
906 auto index = m_transferredImageBitmaps.find(obj);
907 if (index != m_transferredImageBitmaps.end()) {
908 write(ImageBitmapTransferTag);
909 write(index->value);
910 return;
911 }
912
913 // Copying ImageBitmaps is not yet supported.
914 code = SerializationReturnCode::ValidationError;
915 }
916
917 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
918 {
919 if (!value.isCell()) {
920 dumpImmediate(value);
921 return true;
922 }
923 ASSERT(value.isCell());
924
925 if (value.isString()) {
926 dumpString(asString(value)->value(m_exec));
927 return true;
928 }
929
930 if (value.isSymbol()) {
931 code = SerializationReturnCode::DataCloneError;
932 return true;
933 }
934
935 VM& vm = m_exec->vm();
936 if (isArray(vm, value))
937 return false;
938
939 if (value.isObject()) {
940 auto* obj = asObject(value);
941 if (auto* dateObject = jsDynamicCast<DateInstance*>(vm, obj)) {
942 write(DateTag);
943 write(dateObject->internalNumber());
944 return true;
945 }
946 if (auto* booleanObject = jsDynamicCast<BooleanObject*>(vm, obj)) {
947 if (!startObjectInternal(booleanObject)) // handle duplicates
948 return true;
949 write(booleanObject->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
950 return true;
951 }
952 if (auto* stringObject = jsDynamicCast<StringObject*>(vm, obj)) {
953 if (!startObjectInternal(stringObject)) // handle duplicates
954 return true;
955 String str = asString(stringObject->internalValue())->value(m_exec);
956 dumpStringObject(str);
957 return true;
958 }
959 if (auto* numberObject = jsDynamicCast<NumberObject*>(vm, obj)) {
960 if (!startObjectInternal(numberObject)) // handle duplicates
961 return true;
962 write(NumberObjectTag);
963 write(numberObject->internalValue().asNumber());
964 return true;
965 }
966 if (auto* file = JSFile::toWrapped(vm, obj)) {
967 write(FileTag);
968 write(*file);
969 return true;
970 }
971 if (auto* list = JSFileList::toWrapped(vm, obj)) {
972 write(FileListTag);
973 write(list->length());
974 for (auto& file : list->files())
975 write(file.get());
976 return true;
977 }
978 if (auto* blob = JSBlob::toWrapped(vm, obj)) {
979 write(BlobTag);
980 m_blobURLs.append(blob->url());
981 write(blob->url());
982 write(blob->type());
983 write(blob->size());
984 return true;
985 }
986 if (auto* data = JSImageData::toWrapped(vm, obj)) {
987 write(ImageDataTag);
988 write(data->width());
989 write(data->height());
990 write(data->data()->length());
991 write(data->data()->data(), data->data()->length());
992 return true;
993 }
994 if (auto* regExp = jsDynamicCast<RegExpObject*>(vm, obj)) {
995 char flags[3];
996 int flagCount = 0;
997 if (regExp->regExp()->global())
998 flags[flagCount++] = 'g';
999 if (regExp->regExp()->ignoreCase())
1000 flags[flagCount++] = 'i';
1001 if (regExp->regExp()->multiline())
1002 flags[flagCount++] = 'm';
1003 write(RegExpTag);
1004 write(regExp->regExp()->pattern());
1005 write(String(flags, flagCount));
1006 return true;
1007 }
1008 if (obj->inherits<JSMessagePort>(vm)) {
1009 auto index = m_transferredMessagePorts.find(obj);
1010 if (index != m_transferredMessagePorts.end()) {
1011 write(MessagePortReferenceTag);
1012 write(index->value);
1013 return true;
1014 }
1015 // MessagePort object could not be found in transferred message ports
1016 code = SerializationReturnCode::ValidationError;
1017 return true;
1018 }
1019 if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
1020 if (arrayBuffer->isNeutered()) {
1021 code = SerializationReturnCode::ValidationError;
1022 return true;
1023 }
1024 auto index = m_transferredArrayBuffers.find(obj);
1025 if (index != m_transferredArrayBuffers.end()) {
1026 write(ArrayBufferTransferTag);
1027 write(index->value);
1028 return true;
1029 }
1030 if (!startObjectInternal(obj)) // handle duplicates
1031 return true;
1032
1033 if (arrayBuffer->isShared() && m_context == SerializationContext::WorkerPostMessage) {
1034 uint32_t index = m_sharedBuffers.size();
1035 ArrayBufferContents contents;
1036 if (arrayBuffer->shareWith(contents)) {
1037 write(SharedArrayBufferTag);
1038 m_sharedBuffers.append(WTFMove(contents));
1039 write(index);
1040 return true;
1041 }
1042 }
1043
1044 write(ArrayBufferTag);
1045 write(arrayBuffer->byteLength());
1046 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
1047 return true;
1048 }
1049 if (obj->inherits<JSArrayBufferView>(vm)) {
1050 if (checkForDuplicate(obj))
1051 return true;
1052 bool success = dumpArrayBufferView(obj, code);
1053 recordObject(obj);
1054 return success;
1055 }
1056#if ENABLE(WEB_CRYPTO)
1057 if (auto* key = JSCryptoKey::toWrapped(vm, obj)) {
1058 write(CryptoKeyTag);
1059 Vector<uint8_t> serializedKey;
1060 Vector<String> dummyBlobURLs;
1061 PAL::SessionID dummySessionID;
1062 Vector<RefPtr<MessagePort>> dummyMessagePorts;
1063 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
1064#if ENABLE(WEBASSEMBLY)
1065 WasmModuleArray dummyModules;
1066#endif
1067 ArrayBufferContentsArray dummySharedBuffers;
1068 CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, { },
1069#if ENABLE(WEBASSEMBLY)
1070 dummyModules,
1071#endif
1072 dummyBlobURLs, dummySessionID, serializedKey, SerializationContext::Default, dummySharedBuffers);
1073 rawKeySerializer.write(key);
1074 Vector<uint8_t> wrappedKey;
1075 if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey))
1076 return false;
1077 write(wrappedKey);
1078 return true;
1079 }
1080#endif
1081#if ENABLE(WEB_RTC)
1082 if (auto* rtcCertificate = JSRTCCertificate::toWrapped(vm, obj)) {
1083 write(RTCCertificateTag);
1084 write(rtcCertificate->expires());
1085 write(rtcCertificate->pemCertificate());
1086 write(rtcCertificate->origin().toString());
1087 write(rtcCertificate->pemPrivateKey());
1088 write(static_cast<unsigned>(rtcCertificate->getFingerprints().size()));
1089 for (const auto& fingerprint : rtcCertificate->getFingerprints()) {
1090 write(fingerprint.algorithm);
1091 write(fingerprint.value);
1092 }
1093 return true;
1094 }
1095#endif
1096#if ENABLE(WEBASSEMBLY)
1097 if (JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, obj)) {
1098 if (m_context != SerializationContext::WorkerPostMessage && m_context != SerializationContext::WindowPostMessage)
1099 return false;
1100
1101 uint32_t index = m_wasmModules.size();
1102 m_wasmModules.append(makeRef(module->module()));
1103 write(WasmModuleTag);
1104 write(index);
1105 return true;
1106 }
1107#endif
1108 if (obj->inherits<JSDOMPointReadOnly>(vm)) {
1109 dumpDOMPoint(obj);
1110 return true;
1111 }
1112 if (obj->inherits<JSDOMRectReadOnly>(vm)) {
1113 dumpDOMRect(obj);
1114 return true;
1115 }
1116 if (obj->inherits<JSDOMMatrixReadOnly>(vm)) {
1117 dumpDOMMatrix(obj);
1118 return true;
1119 }
1120 if (obj->inherits<JSDOMQuad>(vm)) {
1121 dumpDOMQuad(obj);
1122 return true;
1123 }
1124 if (obj->inherits(vm, JSImageBitmap::info())) {
1125 dumpImageBitmap(obj, code);
1126 return true;
1127 }
1128 return false;
1129 }
1130 // Any other types are expected to serialize as null.
1131 write(NullTag);
1132 return true;
1133 }
1134
1135 void write(SerializationTag tag)
1136 {
1137 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1138 }
1139
1140 void write(ArrayBufferViewSubtag tag)
1141 {
1142 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1143 }
1144
1145#if ENABLE(WEB_CRYPTO)
1146 void write(CryptoKeyClassSubtag tag)
1147 {
1148 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1149 }
1150
1151 void write(CryptoKeyAsymmetricTypeSubtag tag)
1152 {
1153 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1154 }
1155
1156 void write(CryptoKeyUsageTag tag)
1157 {
1158 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1159 }
1160
1161 void write(CryptoAlgorithmIdentifierTag tag)
1162 {
1163 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1164 }
1165#endif
1166
1167 void write(uint8_t c)
1168 {
1169 writeLittleEndian(m_buffer, c);
1170 }
1171
1172 void write(uint32_t i)
1173 {
1174 writeLittleEndian(m_buffer, i);
1175 }
1176
1177 void write(double d)
1178 {
1179 union {
1180 double d;
1181 int64_t i;
1182 } u;
1183 u.d = d;
1184 writeLittleEndian(m_buffer, u.i);
1185 }
1186
1187 void write(int32_t i)
1188 {
1189 writeLittleEndian(m_buffer, i);
1190 }
1191
1192 void write(unsigned long long i)
1193 {
1194 writeLittleEndian(m_buffer, i);
1195 }
1196
1197 void write(uint16_t ch)
1198 {
1199 writeLittleEndian(m_buffer, ch);
1200 }
1201
1202 void writeStringIndex(unsigned i)
1203 {
1204 writeConstantPoolIndex(m_constantPool, i);
1205 }
1206
1207 void writeObjectIndex(unsigned i)
1208 {
1209 writeConstantPoolIndex(m_objectPool, i);
1210 }
1211
1212 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
1213 {
1214 ASSERT(i < constantPool.size());
1215 if (constantPool.size() <= 0xFF)
1216 write(static_cast<uint8_t>(i));
1217 else if (constantPool.size() <= 0xFFFF)
1218 write(static_cast<uint16_t>(i));
1219 else
1220 write(static_cast<uint32_t>(i));
1221 }
1222
1223 void write(const Identifier& ident)
1224 {
1225 const String& str = ident.string();
1226 StringConstantPool::AddResult addResult = m_constantPool.add(ident.impl(), m_constantPool.size());
1227 if (!addResult.isNewEntry) {
1228 write(StringPoolTag);
1229 writeStringIndex(addResult.iterator->value);
1230 return;
1231 }
1232
1233 unsigned length = str.length();
1234
1235 // Guard against overflow
1236 if (length > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
1237 fail();
1238 return;
1239 }
1240
1241 if (str.is8Bit())
1242 writeLittleEndian<uint32_t>(m_buffer, length | StringDataIs8BitFlag);
1243 else
1244 writeLittleEndian<uint32_t>(m_buffer, length);
1245
1246 if (!length)
1247 return;
1248 if (str.is8Bit()) {
1249 if (!writeLittleEndian(m_buffer, str.characters8(), length))
1250 fail();
1251 return;
1252 }
1253 if (!writeLittleEndian(m_buffer, str.characters16(), length))
1254 fail();
1255 }
1256
1257 void write(const String& str)
1258 {
1259 if (str.isNull())
1260 write(m_emptyIdentifier);
1261 else
1262 write(Identifier::fromString(m_exec, str));
1263 }
1264
1265 void write(const Vector<uint8_t>& vector)
1266 {
1267 uint32_t size = vector.size();
1268 write(size);
1269 writeLittleEndian(m_buffer, vector.data(), size);
1270 }
1271
1272 void write(const File& file)
1273 {
1274 m_blobURLs.append(file.url());
1275 write(file.path());
1276 write(file.url());
1277 write(file.type());
1278 write(file.name());
1279 write(static_cast<double>(file.lastModifiedOverride().valueOr(-1)));
1280 }
1281
1282#if ENABLE(WEB_CRYPTO)
1283 void write(CryptoAlgorithmIdentifier algorithm)
1284 {
1285 switch (algorithm) {
1286 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
1287 write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
1288 break;
1289 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
1290 write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
1291 break;
1292 case CryptoAlgorithmIdentifier::RSA_PSS:
1293 write(CryptoAlgorithmIdentifierTag::RSA_PSS);
1294 break;
1295 case CryptoAlgorithmIdentifier::RSA_OAEP:
1296 write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
1297 break;
1298 case CryptoAlgorithmIdentifier::ECDSA:
1299 write(CryptoAlgorithmIdentifierTag::ECDSA);
1300 break;
1301 case CryptoAlgorithmIdentifier::ECDH:
1302 write(CryptoAlgorithmIdentifierTag::ECDH);
1303 break;
1304 case CryptoAlgorithmIdentifier::AES_CTR:
1305 write(CryptoAlgorithmIdentifierTag::AES_CTR);
1306 break;
1307 case CryptoAlgorithmIdentifier::AES_CBC:
1308 write(CryptoAlgorithmIdentifierTag::AES_CBC);
1309 break;
1310 case CryptoAlgorithmIdentifier::AES_GCM:
1311 write(CryptoAlgorithmIdentifierTag::AES_GCM);
1312 break;
1313 case CryptoAlgorithmIdentifier::AES_CFB:
1314 write(CryptoAlgorithmIdentifierTag::AES_CFB);
1315 break;
1316 case CryptoAlgorithmIdentifier::AES_KW:
1317 write(CryptoAlgorithmIdentifierTag::AES_KW);
1318 break;
1319 case CryptoAlgorithmIdentifier::HMAC:
1320 write(CryptoAlgorithmIdentifierTag::HMAC);
1321 break;
1322 case CryptoAlgorithmIdentifier::SHA_1:
1323 write(CryptoAlgorithmIdentifierTag::SHA_1);
1324 break;
1325 case CryptoAlgorithmIdentifier::SHA_224:
1326 write(CryptoAlgorithmIdentifierTag::SHA_224);
1327 break;
1328 case CryptoAlgorithmIdentifier::SHA_256:
1329 write(CryptoAlgorithmIdentifierTag::SHA_256);
1330 break;
1331 case CryptoAlgorithmIdentifier::SHA_384:
1332 write(CryptoAlgorithmIdentifierTag::SHA_384);
1333 break;
1334 case CryptoAlgorithmIdentifier::SHA_512:
1335 write(CryptoAlgorithmIdentifierTag::SHA_512);
1336 break;
1337 case CryptoAlgorithmIdentifier::HKDF:
1338 write(CryptoAlgorithmIdentifierTag::HKDF);
1339 break;
1340 case CryptoAlgorithmIdentifier::PBKDF2:
1341 write(CryptoAlgorithmIdentifierTag::PBKDF2);
1342 break;
1343 }
1344 }
1345
1346 void write(CryptoKeyRSAComponents::Type type)
1347 {
1348 switch (type) {
1349 case CryptoKeyRSAComponents::Type::Public:
1350 write(CryptoKeyAsymmetricTypeSubtag::Public);
1351 return;
1352 case CryptoKeyRSAComponents::Type::Private:
1353 write(CryptoKeyAsymmetricTypeSubtag::Private);
1354 return;
1355 }
1356 }
1357
1358 void write(const CryptoKeyRSAComponents& key)
1359 {
1360 write(key.type());
1361 write(key.modulus());
1362 write(key.exponent());
1363 if (key.type() == CryptoKeyRSAComponents::Type::Public)
1364 return;
1365
1366 write(key.privateExponent());
1367
1368 unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
1369 write(primeCount);
1370 if (!primeCount)
1371 return;
1372
1373 write(key.firstPrimeInfo().primeFactor);
1374 write(key.firstPrimeInfo().factorCRTExponent);
1375 write(key.secondPrimeInfo().primeFactor);
1376 write(key.secondPrimeInfo().factorCRTExponent);
1377 write(key.secondPrimeInfo().factorCRTCoefficient);
1378 for (unsigned i = 2; i < primeCount; ++i) {
1379 write(key.otherPrimeInfos()[i].primeFactor);
1380 write(key.otherPrimeInfos()[i].factorCRTExponent);
1381 write(key.otherPrimeInfos()[i].factorCRTCoefficient);
1382 }
1383 }
1384
1385 void write(const CryptoKey* key)
1386 {
1387 write(currentKeyFormatVersion);
1388
1389 write(key->extractable());
1390
1391 CryptoKeyUsageBitmap usages = key->usagesBitmap();
1392 write(countUsages(usages));
1393 if (usages & CryptoKeyUsageEncrypt)
1394 write(CryptoKeyUsageTag::Encrypt);
1395 if (usages & CryptoKeyUsageDecrypt)
1396 write(CryptoKeyUsageTag::Decrypt);
1397 if (usages & CryptoKeyUsageSign)
1398 write(CryptoKeyUsageTag::Sign);
1399 if (usages & CryptoKeyUsageVerify)
1400 write(CryptoKeyUsageTag::Verify);
1401 if (usages & CryptoKeyUsageDeriveKey)
1402 write(CryptoKeyUsageTag::DeriveKey);
1403 if (usages & CryptoKeyUsageDeriveBits)
1404 write(CryptoKeyUsageTag::DeriveBits);
1405 if (usages & CryptoKeyUsageWrapKey)
1406 write(CryptoKeyUsageTag::WrapKey);
1407 if (usages & CryptoKeyUsageUnwrapKey)
1408 write(CryptoKeyUsageTag::UnwrapKey);
1409
1410 switch (key->keyClass()) {
1411 case CryptoKeyClass::HMAC:
1412 write(CryptoKeyClassSubtag::HMAC);
1413 write(downcast<CryptoKeyHMAC>(*key).key());
1414 write(downcast<CryptoKeyHMAC>(*key).hashAlgorithmIdentifier());
1415 break;
1416 case CryptoKeyClass::AES:
1417 write(CryptoKeyClassSubtag::AES);
1418 write(key->algorithmIdentifier());
1419 write(downcast<CryptoKeyAES>(*key).key());
1420 break;
1421 case CryptoKeyClass::EC:
1422 write(CryptoKeyClassSubtag::EC);
1423 write(key->algorithmIdentifier());
1424 write(downcast<CryptoKeyEC>(*key).namedCurveString());
1425 switch (key->type()) {
1426 case CryptoKey::Type::Public: {
1427 write(CryptoKeyAsymmetricTypeSubtag::Public);
1428 auto result = downcast<CryptoKeyEC>(*key).exportRaw();
1429 ASSERT(!result.hasException());
1430 write(result.releaseReturnValue());
1431 break;
1432 }
1433 case CryptoKey::Type::Private: {
1434 write(CryptoKeyAsymmetricTypeSubtag::Private);
1435 // Use the standard complied method is not very efficient, but simple/reliable.
1436 auto result = downcast<CryptoKeyEC>(*key).exportPkcs8();
1437 ASSERT(!result.hasException());
1438 write(result.releaseReturnValue());
1439 break;
1440 }
1441 default:
1442 ASSERT_NOT_REACHED();
1443 }
1444 break;
1445 case CryptoKeyClass::Raw:
1446 write(CryptoKeyClassSubtag::Raw);
1447 write(key->algorithmIdentifier());
1448 write(downcast<CryptoKeyRaw>(*key).key());
1449 break;
1450 case CryptoKeyClass::RSA:
1451 write(CryptoKeyClassSubtag::RSA);
1452 write(key->algorithmIdentifier());
1453 CryptoAlgorithmIdentifier hash;
1454 bool isRestrictedToHash = downcast<CryptoKeyRSA>(*key).isRestrictedToHash(hash);
1455 write(isRestrictedToHash);
1456 if (isRestrictedToHash)
1457 write(hash);
1458 write(*downcast<CryptoKeyRSA>(*key).exportData());
1459 break;
1460 }
1461 }
1462#endif
1463
1464 void write(const uint8_t* data, unsigned length)
1465 {
1466 m_buffer.append(data, length);
1467 }
1468
1469 Vector<uint8_t>& m_buffer;
1470 Vector<String>& m_blobURLs;
1471 PAL::SessionID m_sessionID;
1472 ObjectPool m_objectPool;
1473 ObjectPool m_transferredMessagePorts;
1474 ObjectPool m_transferredArrayBuffers;
1475 ObjectPool m_transferredImageBitmaps;
1476 typedef HashMap<RefPtr<UniquedStringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
1477 StringConstantPool m_constantPool;
1478 Identifier m_emptyIdentifier;
1479 SerializationContext m_context;
1480 ArrayBufferContentsArray& m_sharedBuffers;
1481#if ENABLE(WEBASSEMBLY)
1482 WasmModuleArray& m_wasmModules;
1483#endif
1484};
1485
1486SerializationReturnCode CloneSerializer::serialize(JSValue in)
1487{
1488 VM& vm = m_exec->vm();
1489 Vector<uint32_t, 16> indexStack;
1490 Vector<uint32_t, 16> lengthStack;
1491 Vector<PropertyNameArray, 16> propertyStack;
1492 Vector<JSObject*, 32> inputObjectStack;
1493 Vector<JSMapIterator*, 4> mapIteratorStack;
1494 Vector<JSSetIterator*, 4> setIteratorStack;
1495 Vector<JSValue, 4> mapIteratorValueStack;
1496 Vector<WalkerState, 16> stateStack;
1497 WalkerState state = StateUnknown;
1498 JSValue inValue = in;
1499 while (1) {
1500 switch (state) {
1501 arrayStartState:
1502 case ArrayStartState: {
1503 ASSERT(isArray(vm, inValue));
1504 if (inputObjectStack.size() > maximumFilterRecursion)
1505 return SerializationReturnCode::StackOverflowError;
1506
1507 JSArray* inArray = asArray(inValue);
1508 unsigned length = inArray->length();
1509 if (!startArray(inArray))
1510 break;
1511 inputObjectStack.append(inArray);
1512 indexStack.append(0);
1513 lengthStack.append(length);
1514 }
1515 arrayStartVisitMember:
1516 FALLTHROUGH;
1517 case ArrayStartVisitMember: {
1518 JSObject* array = inputObjectStack.last();
1519 uint32_t index = indexStack.last();
1520 if (index == lengthStack.last()) {
1521 indexStack.removeLast();
1522 lengthStack.removeLast();
1523
1524 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1525 array->methodTable(vm)->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), EnumerationMode());
1526 if (propertyStack.last().size()) {
1527 write(NonIndexPropertiesTag);
1528 indexStack.append(0);
1529 goto objectStartVisitMember;
1530 }
1531 propertyStack.removeLast();
1532
1533 endObject();
1534 inputObjectStack.removeLast();
1535 break;
1536 }
1537 inValue = array->getDirectIndex(m_exec, index);
1538 if (!inValue) {
1539 indexStack.last()++;
1540 goto arrayStartVisitMember;
1541 }
1542
1543 write(index);
1544 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1545 if (dumpIfTerminal(inValue, terminalCode)) {
1546 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1547 return terminalCode;
1548 indexStack.last()++;
1549 goto arrayStartVisitMember;
1550 }
1551 stateStack.append(ArrayEndVisitMember);
1552 goto stateUnknown;
1553 }
1554 case ArrayEndVisitMember: {
1555 indexStack.last()++;
1556 goto arrayStartVisitMember;
1557 }
1558 objectStartState:
1559 case ObjectStartState: {
1560 ASSERT(inValue.isObject());
1561 if (inputObjectStack.size() > maximumFilterRecursion)
1562 return SerializationReturnCode::StackOverflowError;
1563 JSObject* inObject = asObject(inValue);
1564 if (!startObject(inObject))
1565 break;
1566 // At this point, all supported objects other than Object
1567 // objects have been handled. If we reach this point and
1568 // the input is not an Object object then we should throw
1569 // a DataCloneError.
1570 if (inObject->classInfo(vm) != JSFinalObject::info())
1571 return SerializationReturnCode::DataCloneError;
1572 inputObjectStack.append(inObject);
1573 indexStack.append(0);
1574 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1575 inObject->methodTable(vm)->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), EnumerationMode());
1576 }
1577 objectStartVisitMember:
1578 FALLTHROUGH;
1579 case ObjectStartVisitMember: {
1580 JSObject* object = inputObjectStack.last();
1581 uint32_t index = indexStack.last();
1582 PropertyNameArray& properties = propertyStack.last();
1583 if (index == properties.size()) {
1584 endObject();
1585 inputObjectStack.removeLast();
1586 indexStack.removeLast();
1587 propertyStack.removeLast();
1588 break;
1589 }
1590 inValue = getProperty(vm, object, properties[index]);
1591 if (shouldTerminate())
1592 return SerializationReturnCode::ExistingExceptionError;
1593
1594 if (!inValue) {
1595 // Property was removed during serialisation
1596 indexStack.last()++;
1597 goto objectStartVisitMember;
1598 }
1599 write(properties[index]);
1600
1601 if (shouldTerminate())
1602 return SerializationReturnCode::ExistingExceptionError;
1603
1604 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1605 if (!dumpIfTerminal(inValue, terminalCode)) {
1606 stateStack.append(ObjectEndVisitMember);
1607 goto stateUnknown;
1608 }
1609 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1610 return terminalCode;
1611 FALLTHROUGH;
1612 }
1613 case ObjectEndVisitMember: {
1614 if (shouldTerminate())
1615 return SerializationReturnCode::ExistingExceptionError;
1616
1617 indexStack.last()++;
1618 goto objectStartVisitMember;
1619 }
1620 mapStartState: {
1621 ASSERT(inValue.isObject());
1622 if (inputObjectStack.size() > maximumFilterRecursion)
1623 return SerializationReturnCode::StackOverflowError;
1624 JSMap* inMap = jsCast<JSMap*>(inValue);
1625 if (!startMap(inMap))
1626 break;
1627 JSMapIterator* iterator = JSMapIterator::create(vm, vm.mapIteratorStructure(), inMap, IterateKeyValue);
1628 m_gcBuffer.appendWithCrashOnOverflow(inMap);
1629 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1630 mapIteratorStack.append(iterator);
1631 inputObjectStack.append(inMap);
1632 goto mapDataStartVisitEntry;
1633 }
1634 mapDataStartVisitEntry:
1635 case MapDataStartVisitEntry: {
1636 JSMapIterator* iterator = mapIteratorStack.last();
1637 JSValue key, value;
1638 if (!iterator->nextKeyValue(m_exec, key, value)) {
1639 mapIteratorStack.removeLast();
1640 JSObject* object = inputObjectStack.last();
1641 ASSERT(jsDynamicCast<JSMap*>(vm, object));
1642 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1643 object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1644 write(NonMapPropertiesTag);
1645 indexStack.append(0);
1646 goto objectStartVisitMember;
1647 }
1648 inValue = key;
1649 m_gcBuffer.appendWithCrashOnOverflow(value);
1650 mapIteratorValueStack.append(value);
1651 stateStack.append(MapDataEndVisitKey);
1652 goto stateUnknown;
1653 }
1654 case MapDataEndVisitKey: {
1655 inValue = mapIteratorValueStack.last();
1656 mapIteratorValueStack.removeLast();
1657 stateStack.append(MapDataEndVisitValue);
1658 goto stateUnknown;
1659 }
1660 case MapDataEndVisitValue: {
1661 goto mapDataStartVisitEntry;
1662 }
1663
1664 setStartState: {
1665 ASSERT(inValue.isObject());
1666 if (inputObjectStack.size() > maximumFilterRecursion)
1667 return SerializationReturnCode::StackOverflowError;
1668 JSSet* inSet = jsCast<JSSet*>(inValue);
1669 if (!startSet(inSet))
1670 break;
1671 JSSetIterator* iterator = JSSetIterator::create(vm, vm.setIteratorStructure(), inSet, IterateKey);
1672 m_gcBuffer.appendWithCrashOnOverflow(inSet);
1673 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1674 setIteratorStack.append(iterator);
1675 inputObjectStack.append(inSet);
1676 goto setDataStartVisitEntry;
1677 }
1678 setDataStartVisitEntry:
1679 case SetDataStartVisitEntry: {
1680 JSSetIterator* iterator = setIteratorStack.last();
1681 JSValue key;
1682 if (!iterator->next(m_exec, key)) {
1683 setIteratorStack.removeLast();
1684 JSObject* object = inputObjectStack.last();
1685 ASSERT(jsDynamicCast<JSSet*>(vm, object));
1686 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1687 object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1688 write(NonSetPropertiesTag);
1689 indexStack.append(0);
1690 goto objectStartVisitMember;
1691 }
1692 inValue = key;
1693 stateStack.append(SetDataEndVisitKey);
1694 goto stateUnknown;
1695 }
1696 case SetDataEndVisitKey: {
1697 goto setDataStartVisitEntry;
1698 }
1699
1700 stateUnknown:
1701 case StateUnknown: {
1702 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1703 if (dumpIfTerminal(inValue, terminalCode)) {
1704 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1705 return terminalCode;
1706 break;
1707 }
1708
1709 if (isArray(vm, inValue))
1710 goto arrayStartState;
1711 if (isMap(vm, inValue))
1712 goto mapStartState;
1713 if (isSet(vm, inValue))
1714 goto setStartState;
1715 goto objectStartState;
1716 }
1717 }
1718 if (stateStack.isEmpty())
1719 break;
1720
1721 state = stateStack.last();
1722 stateStack.removeLast();
1723 }
1724 if (m_failed)
1725 return SerializationReturnCode::UnspecifiedError;
1726
1727 return SerializationReturnCode::SuccessfullyCompleted;
1728}
1729
1730class CloneDeserializer : CloneBase {
1731public:
1732 static String deserializeString(const Vector<uint8_t>& buffer)
1733 {
1734 if (buffer.isEmpty())
1735 return String();
1736 const uint8_t* ptr = buffer.begin();
1737 const uint8_t* end = buffer.end();
1738 uint32_t version;
1739 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1740 return String();
1741 uint8_t tag;
1742 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1743 return String();
1744 uint32_t length;
1745 if (!readLittleEndian(ptr, end, length))
1746 return String();
1747 bool is8Bit = length & StringDataIs8BitFlag;
1748 length &= ~StringDataIs8BitFlag;
1749 String str;
1750 if (!readString(ptr, end, str, length, is8Bit))
1751 return String();
1752 return str;
1753 }
1754
1755 static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
1756#if ENABLE(WEBASSEMBLY)
1757 , WasmModuleArray* wasmModules
1758#endif
1759 )
1760 {
1761 if (!buffer.size())
1762 return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
1763 CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, sessionID, blobFilePaths, sharedBuffers, WTFMove(imageBuffers)
1764#if ENABLE(WEBASSEMBLY)
1765 , wasmModules
1766#endif
1767 );
1768 if (!deserializer.isValid())
1769 return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
1770 return deserializer.deserialize();
1771 }
1772
1773private:
1774 struct CachedString {
1775 CachedString(const String& string)
1776 : m_string(string)
1777 {
1778 }
1779
1780 JSValue jsString(ExecState* exec)
1781 {
1782 if (!m_jsString)
1783 m_jsString = JSC::jsString(exec, m_string);
1784 return m_jsString;
1785 }
1786 const String& string() { return m_string; }
1787 String takeString() { return WTFMove(m_string); }
1788
1789 private:
1790 String m_string;
1791 JSValue m_jsString;
1792 };
1793
1794 struct CachedStringRef {
1795 CachedStringRef()
1796 : m_base(0)
1797 , m_index(0)
1798 {
1799 }
1800 CachedStringRef(Vector<CachedString>* base, size_t index)
1801 : m_base(base)
1802 , m_index(index)
1803 {
1804 }
1805
1806 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1807
1808 private:
1809 Vector<CachedString>* m_base;
1810 size_t m_index;
1811 };
1812
1813 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers,
1814#if ENABLE(WEBASSEMBLY)
1815 WasmModuleArray* wasmModules,
1816#endif
1817 const Vector<uint8_t>& buffer)
1818 : CloneBase(exec)
1819 , m_globalObject(globalObject)
1820 , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1821 , m_ptr(buffer.data())
1822 , m_end(buffer.data() + buffer.size())
1823 , m_version(0xFFFFFFFF)
1824 , m_messagePorts(messagePorts)
1825 , m_arrayBufferContents(arrayBufferContents)
1826 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1827 , m_imageBuffers(WTFMove(imageBuffers))
1828 , m_imageBitmaps(m_imageBuffers.size())
1829#if ENABLE(WEBASSEMBLY)
1830 , m_wasmModules(wasmModules)
1831#endif
1832 {
1833 if (!read(m_version))
1834 m_version = 0xFFFFFFFF;
1835 }
1836
1837 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers
1838#if ENABLE(WEBASSEMBLY)
1839 , WasmModuleArray* wasmModules
1840#endif
1841 )
1842 : CloneBase(exec)
1843 , m_globalObject(globalObject)
1844 , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1845 , m_ptr(buffer.data())
1846 , m_end(buffer.data() + buffer.size())
1847 , m_version(0xFFFFFFFF)
1848 , m_messagePorts(messagePorts)
1849 , m_arrayBufferContents(arrayBufferContents)
1850 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1851 , m_blobURLs(blobURLs)
1852 , m_sessionID(sessionID)
1853 , m_blobFilePaths(blobFilePaths)
1854 , m_sharedBuffers(sharedBuffers)
1855 , m_imageBuffers(WTFMove(imageBuffers))
1856 , m_imageBitmaps(m_imageBuffers.size())
1857#if ENABLE(WEBASSEMBLY)
1858 , m_wasmModules(wasmModules)
1859#endif
1860 {
1861 if (!read(m_version))
1862 m_version = 0xFFFFFFFF;
1863 }
1864
1865 DeserializationResult deserialize();
1866
1867 bool isValid() const { return m_version <= CurrentVersion; }
1868
1869 template <typename T> bool readLittleEndian(T& value)
1870 {
1871 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1872 fail();
1873 return false;
1874 }
1875 return true;
1876 }
1877#if ASSUME_LITTLE_ENDIAN
1878 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1879 {
1880 if (ptr > end - sizeof(value))
1881 return false;
1882
1883 if (sizeof(T) == 1)
1884 value = *ptr++;
1885 else {
1886 value = *reinterpret_cast<const T*>(ptr);
1887 ptr += sizeof(T);
1888 }
1889 return true;
1890 }
1891#else
1892 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1893 {
1894 if (ptr > end - sizeof(value))
1895 return false;
1896
1897 if (sizeof(T) == 1)
1898 value = *ptr++;
1899 else {
1900 value = 0;
1901 for (unsigned i = 0; i < sizeof(T); i++)
1902 value += ((T)*ptr++) << (i * 8);
1903 }
1904 return true;
1905 }
1906#endif
1907
1908 bool read(uint32_t& i)
1909 {
1910 return readLittleEndian(i);
1911 }
1912
1913 bool read(int32_t& i)
1914 {
1915 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1916 }
1917
1918 bool read(uint16_t& i)
1919 {
1920 return readLittleEndian(i);
1921 }
1922
1923 bool read(uint8_t& i)
1924 {
1925 return readLittleEndian(i);
1926 }
1927
1928 bool read(double& d)
1929 {
1930 union {
1931 double d;
1932 uint64_t i64;
1933 } u;
1934 if (!readLittleEndian(u.i64))
1935 return false;
1936 d = u.d;
1937 return true;
1938 }
1939
1940 bool read(unsigned long long& i)
1941 {
1942 return readLittleEndian(i);
1943 }
1944
1945 bool readStringIndex(uint32_t& i)
1946 {
1947 return readConstantPoolIndex(m_constantPool, i);
1948 }
1949
1950 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1951 {
1952 if (constantPool.size() <= 0xFF) {
1953 uint8_t i8;
1954 if (!read(i8))
1955 return false;
1956 i = i8;
1957 return true;
1958 }
1959 if (constantPool.size() <= 0xFFFF) {
1960 uint16_t i16;
1961 if (!read(i16))
1962 return false;
1963 i = i16;
1964 return true;
1965 }
1966 return read(i);
1967 }
1968
1969 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit)
1970 {
1971 if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar))
1972 return false;
1973
1974 if (is8Bit) {
1975 if ((end - ptr) < static_cast<int>(length))
1976 return false;
1977 str = String(reinterpret_cast<const LChar*>(ptr), length);
1978 ptr += length;
1979 return true;
1980 }
1981
1982 unsigned size = length * sizeof(UChar);
1983 if ((end - ptr) < static_cast<int>(size))
1984 return false;
1985
1986#if ASSUME_LITTLE_ENDIAN
1987 str = String(reinterpret_cast<const UChar*>(ptr), length);
1988 ptr += length * sizeof(UChar);
1989#else
1990 Vector<UChar> buffer;
1991 buffer.reserveCapacity(length);
1992 for (unsigned i = 0; i < length; i++) {
1993 uint16_t ch;
1994 readLittleEndian(ptr, end, ch);
1995 buffer.append(ch);
1996 }
1997 str = String::adopt(WTFMove(buffer));
1998#endif
1999 return true;
2000 }
2001
2002 bool readStringData(CachedStringRef& cachedString)
2003 {
2004 bool scratch;
2005 return readStringData(cachedString, scratch);
2006 }
2007
2008 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
2009 {
2010 if (m_failed)
2011 return false;
2012 uint32_t length = 0;
2013 if (!read(length))
2014 return false;
2015 if (length == TerminatorTag) {
2016 wasTerminator = true;
2017 return false;
2018 }
2019 if (length == StringPoolTag) {
2020 unsigned index = 0;
2021 if (!readStringIndex(index)) {
2022 fail();
2023 return false;
2024 }
2025 if (index >= m_constantPool.size()) {
2026 fail();
2027 return false;
2028 }
2029 cachedString = CachedStringRef(&m_constantPool, index);
2030 return true;
2031 }
2032 bool is8Bit = length & StringDataIs8BitFlag;
2033 length &= ~StringDataIs8BitFlag;
2034 String str;
2035 if (!readString(m_ptr, m_end, str, length, is8Bit)) {
2036 fail();
2037 return false;
2038 }
2039 m_constantPool.append(str);
2040 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
2041 return true;
2042 }
2043
2044 SerializationTag readTag()
2045 {
2046 if (m_ptr >= m_end)
2047 return ErrorTag;
2048 return static_cast<SerializationTag>(*m_ptr++);
2049 }
2050
2051 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
2052 {
2053 if (m_ptr >= m_end)
2054 return false;
2055 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
2056 return true;
2057 }
2058
2059 void putProperty(JSObject* object, unsigned index, JSValue value)
2060 {
2061 object->putDirectIndex(m_exec, index, value);
2062 }
2063
2064 void putProperty(JSObject* object, const Identifier& property, JSValue value)
2065 {
2066 object->putDirectMayBeIndex(m_exec, property, value);
2067 }
2068
2069 bool readFile(RefPtr<File>& file)
2070 {
2071 CachedStringRef path;
2072 if (!readStringData(path))
2073 return false;
2074 CachedStringRef url;
2075 if (!readStringData(url))
2076 return false;
2077 CachedStringRef type;
2078 if (!readStringData(type))
2079 return false;
2080 CachedStringRef name;
2081 if (!readStringData(name))
2082 return false;
2083 Optional<int64_t> optionalLastModified;
2084 if (m_version > 6) {
2085 double lastModified;
2086 if (!read(lastModified))
2087 return false;
2088 if (lastModified >= 0)
2089 optionalLastModified = lastModified;
2090 }
2091
2092 // If the blob URL for this file has an associated blob file path, prefer that one over the "built-in" path.
2093 String filePath = blobFilePathForBlobURL(url->string());
2094 if (filePath.isEmpty())
2095 filePath = path->string();
2096
2097 if (m_isDOMGlobalObject)
2098 file = File::deserialize(filePath, URL(URL(), url->string()), type->string(), name->string(), optionalLastModified);
2099 return true;
2100 }
2101
2102 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
2103 {
2104 uint32_t length;
2105 if (!read(length))
2106 return false;
2107 if (m_ptr + length > m_end)
2108 return false;
2109 arrayBuffer = ArrayBuffer::create(m_ptr, length);
2110 m_ptr += length;
2111 return true;
2112 }
2113
2114 bool readArrayBufferView(VM& vm, JSValue& arrayBufferView)
2115 {
2116 ArrayBufferViewSubtag arrayBufferViewSubtag;
2117 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
2118 return false;
2119 uint32_t byteOffset;
2120 if (!read(byteOffset))
2121 return false;
2122 uint32_t byteLength;
2123 if (!read(byteLength))
2124 return false;
2125 JSObject* arrayBufferObj = asObject(readTerminal());
2126 if (!arrayBufferObj || !arrayBufferObj->inherits<JSArrayBuffer>(vm))
2127 return false;
2128
2129 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
2130 if (!elementSize)
2131 return false;
2132 unsigned length = byteLength / elementSize;
2133 if (length * elementSize != byteLength)
2134 return false;
2135
2136 RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(vm, arrayBufferObj);
2137 switch (arrayBufferViewSubtag) {
2138 case DataViewTag:
2139 arrayBufferView = getJSValue(DataView::create(WTFMove(arrayBuffer), byteOffset, length).get());
2140 return true;
2141 case Int8ArrayTag:
2142 arrayBufferView = toJS(m_exec, m_globalObject, Int8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2143 return true;
2144 case Uint8ArrayTag:
2145 arrayBufferView = toJS(m_exec, m_globalObject, Uint8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2146 return true;
2147 case Uint8ClampedArrayTag:
2148 arrayBufferView = toJS(m_exec, m_globalObject, Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2149 return true;
2150 case Int16ArrayTag:
2151 arrayBufferView = toJS(m_exec, m_globalObject, Int16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2152 return true;
2153 case Uint16ArrayTag:
2154 arrayBufferView = toJS(m_exec, m_globalObject, Uint16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2155 return true;
2156 case Int32ArrayTag:
2157 arrayBufferView = toJS(m_exec, m_globalObject, Int32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2158 return true;
2159 case Uint32ArrayTag:
2160 arrayBufferView = toJS(m_exec, m_globalObject, Uint32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2161 return true;
2162 case Float32ArrayTag:
2163 arrayBufferView = toJS(m_exec, m_globalObject, Float32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2164 return true;
2165 case Float64ArrayTag:
2166 arrayBufferView = toJS(m_exec, m_globalObject, Float64Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2167 return true;
2168 default:
2169 return false;
2170 }
2171 }
2172
2173 bool read(Vector<uint8_t>& result)
2174 {
2175 ASSERT(result.isEmpty());
2176 uint32_t size;
2177 if (!read(size))
2178 return false;
2179 if (m_ptr + size > m_end)
2180 return false;
2181 result.append(m_ptr, size);
2182 m_ptr += size;
2183 return true;
2184 }
2185
2186#if ENABLE(WEB_CRYPTO)
2187 bool read(CryptoAlgorithmIdentifier& result)
2188 {
2189 uint8_t algorithmTag;
2190 if (!read(algorithmTag))
2191 return false;
2192 if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
2193 return false;
2194 switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
2195 case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
2196 result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
2197 break;
2198 case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
2199 result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
2200 break;
2201 case CryptoAlgorithmIdentifierTag::RSA_PSS:
2202 result = CryptoAlgorithmIdentifier::RSA_PSS;
2203 break;
2204 case CryptoAlgorithmIdentifierTag::RSA_OAEP:
2205 result = CryptoAlgorithmIdentifier::RSA_OAEP;
2206 break;
2207 case CryptoAlgorithmIdentifierTag::ECDSA:
2208 result = CryptoAlgorithmIdentifier::ECDSA;
2209 break;
2210 case CryptoAlgorithmIdentifierTag::ECDH:
2211 result = CryptoAlgorithmIdentifier::ECDH;
2212 break;
2213 case CryptoAlgorithmIdentifierTag::AES_CTR:
2214 result = CryptoAlgorithmIdentifier::AES_CTR;
2215 break;
2216 case CryptoAlgorithmIdentifierTag::AES_CBC:
2217 result = CryptoAlgorithmIdentifier::AES_CBC;
2218 break;
2219 case CryptoAlgorithmIdentifierTag::AES_GCM:
2220 result = CryptoAlgorithmIdentifier::AES_GCM;
2221 break;
2222 case CryptoAlgorithmIdentifierTag::AES_CFB:
2223 result = CryptoAlgorithmIdentifier::AES_CFB;
2224 break;
2225 case CryptoAlgorithmIdentifierTag::AES_KW:
2226 result = CryptoAlgorithmIdentifier::AES_KW;
2227 break;
2228 case CryptoAlgorithmIdentifierTag::HMAC:
2229 result = CryptoAlgorithmIdentifier::HMAC;
2230 break;
2231 case CryptoAlgorithmIdentifierTag::SHA_1:
2232 result = CryptoAlgorithmIdentifier::SHA_1;
2233 break;
2234 case CryptoAlgorithmIdentifierTag::SHA_224:
2235 result = CryptoAlgorithmIdentifier::SHA_224;
2236 break;
2237 case CryptoAlgorithmIdentifierTag::SHA_256:
2238 result = CryptoAlgorithmIdentifier::SHA_256;
2239 break;
2240 case CryptoAlgorithmIdentifierTag::SHA_384:
2241 result = CryptoAlgorithmIdentifier::SHA_384;
2242 break;
2243 case CryptoAlgorithmIdentifierTag::SHA_512:
2244 result = CryptoAlgorithmIdentifier::SHA_512;
2245 break;
2246 case CryptoAlgorithmIdentifierTag::HKDF:
2247 result = CryptoAlgorithmIdentifier::HKDF;
2248 break;
2249 case CryptoAlgorithmIdentifierTag::PBKDF2:
2250 result = CryptoAlgorithmIdentifier::PBKDF2;
2251 break;
2252 }
2253 return true;
2254 }
2255
2256 bool read(CryptoKeyClassSubtag& result)
2257 {
2258 uint8_t tag;
2259 if (!read(tag))
2260 return false;
2261 if (tag > cryptoKeyClassSubtagMaximumValue)
2262 return false;
2263 result = static_cast<CryptoKeyClassSubtag>(tag);
2264 return true;
2265 }
2266
2267 bool read(CryptoKeyUsageTag& result)
2268 {
2269 uint8_t tag;
2270 if (!read(tag))
2271 return false;
2272 if (tag > cryptoKeyUsageTagMaximumValue)
2273 return false;
2274 result = static_cast<CryptoKeyUsageTag>(tag);
2275 return true;
2276 }
2277
2278 bool read(CryptoKeyAsymmetricTypeSubtag& result)
2279 {
2280 uint8_t tag;
2281 if (!read(tag))
2282 return false;
2283 if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
2284 return false;
2285 result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
2286 return true;
2287 }
2288
2289 bool readHMACKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2290 {
2291 Vector<uint8_t> keyData;
2292 if (!read(keyData))
2293 return false;
2294 CryptoAlgorithmIdentifier hash;
2295 if (!read(hash))
2296 return false;
2297 result = CryptoKeyHMAC::importRaw(0, hash, WTFMove(keyData), extractable, usages);
2298 return true;
2299 }
2300
2301 bool readAESKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2302 {
2303 CryptoAlgorithmIdentifier algorithm;
2304 if (!read(algorithm))
2305 return false;
2306 if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
2307 return false;
2308 Vector<uint8_t> keyData;
2309 if (!read(keyData))
2310 return false;
2311 result = CryptoKeyAES::importRaw(algorithm, WTFMove(keyData), extractable, usages);
2312 return true;
2313 }
2314
2315 bool readRSAKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2316 {
2317 CryptoAlgorithmIdentifier algorithm;
2318 if (!read(algorithm))
2319 return false;
2320
2321 int32_t isRestrictedToHash;
2322 CryptoAlgorithmIdentifier hash;
2323 if (!read(isRestrictedToHash))
2324 return false;
2325 if (isRestrictedToHash && !read(hash))
2326 return false;
2327
2328 CryptoKeyAsymmetricTypeSubtag type;
2329 if (!read(type))
2330 return false;
2331
2332 Vector<uint8_t> modulus;
2333 if (!read(modulus))
2334 return false;
2335 Vector<uint8_t> exponent;
2336 if (!read(exponent))
2337 return false;
2338
2339 if (type == CryptoKeyAsymmetricTypeSubtag::Public) {
2340 auto keyData = CryptoKeyRSAComponents::createPublic(modulus, exponent);
2341 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2342 result = WTFMove(key);
2343 return true;
2344 }
2345
2346 Vector<uint8_t> privateExponent;
2347 if (!read(privateExponent))
2348 return false;
2349
2350 uint32_t primeCount;
2351 if (!read(primeCount))
2352 return false;
2353
2354 if (!primeCount) {
2355 auto keyData = CryptoKeyRSAComponents::createPrivate(modulus, exponent, privateExponent);
2356 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2357 result = WTFMove(key);
2358 return true;
2359 }
2360
2361 if (primeCount < 2)
2362 return false;
2363
2364 CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
2365 CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
2366 Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
2367
2368 if (!read(firstPrimeInfo.primeFactor))
2369 return false;
2370 if (!read(firstPrimeInfo.factorCRTExponent))
2371 return false;
2372 if (!read(secondPrimeInfo.primeFactor))
2373 return false;
2374 if (!read(secondPrimeInfo.factorCRTExponent))
2375 return false;
2376 if (!read(secondPrimeInfo.factorCRTCoefficient))
2377 return false;
2378 for (unsigned i = 2; i < primeCount; ++i) {
2379 if (!read(otherPrimeInfos[i].primeFactor))
2380 return false;
2381 if (!read(otherPrimeInfos[i].factorCRTExponent))
2382 return false;
2383 if (!read(otherPrimeInfos[i].factorCRTCoefficient))
2384 return false;
2385 }
2386
2387 auto keyData = CryptoKeyRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
2388 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2389 result = WTFMove(key);
2390 return true;
2391 }
2392
2393 bool readECKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2394 {
2395 CryptoAlgorithmIdentifier algorithm;
2396 if (!read(algorithm))
2397 return false;
2398 if (!CryptoKeyEC::isValidECAlgorithm(algorithm))
2399 return false;
2400 CachedStringRef curve;
2401 if (!readStringData(curve))
2402 return false;
2403 CryptoKeyAsymmetricTypeSubtag type;
2404 if (!read(type))
2405 return false;
2406 Vector<uint8_t> keyData;
2407 if (!read(keyData))
2408 return false;
2409
2410 switch (type) {
2411 case CryptoKeyAsymmetricTypeSubtag::Public:
2412 result = CryptoKeyEC::importRaw(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2413 break;
2414 case CryptoKeyAsymmetricTypeSubtag::Private:
2415 result = CryptoKeyEC::importPkcs8(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2416 break;
2417 }
2418
2419 return true;
2420 }
2421
2422 bool readRawKey(CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2423 {
2424 CryptoAlgorithmIdentifier algorithm;
2425 if (!read(algorithm))
2426 return false;
2427 Vector<uint8_t> keyData;
2428 if (!read(keyData))
2429 return false;
2430 result = CryptoKeyRaw::create(algorithm, WTFMove(keyData), usages);
2431 return true;
2432 }
2433
2434 bool readCryptoKey(JSValue& cryptoKey)
2435 {
2436 uint32_t keyFormatVersion;
2437 if (!read(keyFormatVersion) || keyFormatVersion > currentKeyFormatVersion)
2438 return false;
2439
2440 int32_t extractable;
2441 if (!read(extractable))
2442 return false;
2443
2444 uint32_t usagesCount;
2445 if (!read(usagesCount))
2446 return false;
2447
2448 CryptoKeyUsageBitmap usages = 0;
2449 for (uint32_t i = 0; i < usagesCount; ++i) {
2450 CryptoKeyUsageTag usage;
2451 if (!read(usage))
2452 return false;
2453 switch (usage) {
2454 case CryptoKeyUsageTag::Encrypt:
2455 usages |= CryptoKeyUsageEncrypt;
2456 break;
2457 case CryptoKeyUsageTag::Decrypt:
2458 usages |= CryptoKeyUsageDecrypt;
2459 break;
2460 case CryptoKeyUsageTag::Sign:
2461 usages |= CryptoKeyUsageSign;
2462 break;
2463 case CryptoKeyUsageTag::Verify:
2464 usages |= CryptoKeyUsageVerify;
2465 break;
2466 case CryptoKeyUsageTag::DeriveKey:
2467 usages |= CryptoKeyUsageDeriveKey;
2468 break;
2469 case CryptoKeyUsageTag::DeriveBits:
2470 usages |= CryptoKeyUsageDeriveBits;
2471 break;
2472 case CryptoKeyUsageTag::WrapKey:
2473 usages |= CryptoKeyUsageWrapKey;
2474 break;
2475 case CryptoKeyUsageTag::UnwrapKey:
2476 usages |= CryptoKeyUsageUnwrapKey;
2477 break;
2478 }
2479 }
2480
2481 CryptoKeyClassSubtag cryptoKeyClass;
2482 if (!read(cryptoKeyClass))
2483 return false;
2484 RefPtr<CryptoKey> result;
2485 switch (cryptoKeyClass) {
2486 case CryptoKeyClassSubtag::HMAC:
2487 if (!readHMACKey(extractable, usages, result))
2488 return false;
2489 break;
2490 case CryptoKeyClassSubtag::AES:
2491 if (!readAESKey(extractable, usages, result))
2492 return false;
2493 break;
2494 case CryptoKeyClassSubtag::RSA:
2495 if (!readRSAKey(extractable, usages, result))
2496 return false;
2497 break;
2498 case CryptoKeyClassSubtag::EC:
2499 if (!readECKey(extractable, usages, result))
2500 return false;
2501 break;
2502 case CryptoKeyClassSubtag::Raw:
2503 if (!readRawKey(usages, result))
2504 return false;
2505 break;
2506 }
2507 cryptoKey = getJSValue(result.get());
2508 return true;
2509 }
2510#endif
2511
2512 template<class T>
2513 JSValue getJSValue(T* nativeObj)
2514 {
2515 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2516 }
2517
2518 template<class T>
2519 JSValue getJSValue(T& nativeObj)
2520 {
2521 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2522 }
2523
2524 template<class T>
2525 JSValue readDOMPoint()
2526 {
2527 double x;
2528 if (!read(x))
2529 return { };
2530 double y;
2531 if (!read(y))
2532 return { };
2533 double z;
2534 if (!read(z))
2535 return { };
2536 double w;
2537 if (!read(w))
2538 return { };
2539
2540 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, z, w));
2541 }
2542
2543 template<class T>
2544 JSValue readDOMMatrix()
2545 {
2546 uint8_t is2D;
2547 if (!read(is2D))
2548 return { };
2549
2550 if (is2D) {
2551 double m11;
2552 if (!read(m11))
2553 return { };
2554 double m12;
2555 if (!read(m12))
2556 return { };
2557 double m21;
2558 if (!read(m21))
2559 return { };
2560 double m22;
2561 if (!read(m22))
2562 return { };
2563 double m41;
2564 if (!read(m41))
2565 return { };
2566 double m42;
2567 if (!read(m42))
2568 return { };
2569
2570 TransformationMatrix matrix(m11, m12, m21, m22, m41, m42);
2571 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::Yes));
2572 } else {
2573 double m11;
2574 if (!read(m11))
2575 return { };
2576 double m12;
2577 if (!read(m12))
2578 return { };
2579 double m13;
2580 if (!read(m13))
2581 return { };
2582 double m14;
2583 if (!read(m14))
2584 return { };
2585 double m21;
2586 if (!read(m21))
2587 return { };
2588 double m22;
2589 if (!read(m22))
2590 return { };
2591 double m23;
2592 if (!read(m23))
2593 return { };
2594 double m24;
2595 if (!read(m24))
2596 return { };
2597 double m31;
2598 if (!read(m31))
2599 return { };
2600 double m32;
2601 if (!read(m32))
2602 return { };
2603 double m33;
2604 if (!read(m33))
2605 return { };
2606 double m34;
2607 if (!read(m34))
2608 return { };
2609 double m41;
2610 if (!read(m41))
2611 return { };
2612 double m42;
2613 if (!read(m42))
2614 return { };
2615 double m43;
2616 if (!read(m43))
2617 return { };
2618 double m44;
2619 if (!read(m44))
2620 return { };
2621
2622 TransformationMatrix matrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
2623 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::No));
2624 }
2625 }
2626
2627 template<class T>
2628 JSValue readDOMRect()
2629 {
2630 double x;
2631 if (!read(x))
2632 return { };
2633 double y;
2634 if (!read(y))
2635 return { };
2636 double width;
2637 if (!read(width))
2638 return { };
2639 double height;
2640 if (!read(height))
2641 return { };
2642
2643 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, width, height));
2644 }
2645
2646 Optional<DOMPointInit> readDOMPointInit()
2647 {
2648 DOMPointInit point;
2649 if (!read(point.x))
2650 return WTF::nullopt;
2651 if (!read(point.y))
2652 return WTF::nullopt;
2653 if (!read(point.z))
2654 return WTF::nullopt;
2655 if (!read(point.w))
2656 return WTF::nullopt;
2657
2658 return point;
2659 }
2660
2661 JSValue readDOMQuad()
2662 {
2663 auto p1 = readDOMPointInit();
2664 if (!p1)
2665 return JSValue();
2666 auto p2 = readDOMPointInit();
2667 if (!p2)
2668 return JSValue();
2669 auto p3 = readDOMPointInit();
2670 if (!p3)
2671 return JSValue();
2672 auto p4 = readDOMPointInit();
2673 if (!p4)
2674 return JSValue();
2675
2676 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), DOMQuad::create(p1.value(), p2.value(), p3.value(), p4.value()));
2677 }
2678
2679 JSValue readImageBitmap()
2680 {
2681 uint32_t index;
2682 bool indexSuccessfullyRead = read(index);
2683 if (!indexSuccessfullyRead || index >= m_imageBuffers.size()) {
2684 fail();
2685 return JSValue();
2686 }
2687
2688 if (!m_imageBitmaps[index])
2689 m_imageBitmaps[index] = ImageBitmap::create(WTFMove(m_imageBuffers.at(index)));
2690
2691 auto bitmap = m_imageBitmaps[index].get();
2692 return getJSValue(bitmap);
2693 }
2694
2695#if ENABLE(WEB_RTC)
2696 JSValue readRTCCertificate()
2697 {
2698 double expires;
2699 if (!read(expires)) {
2700 fail();
2701 return JSValue();
2702 }
2703 CachedStringRef certificate;
2704 if (!readStringData(certificate)) {
2705 fail();
2706 return JSValue();
2707 }
2708 CachedStringRef origin;
2709 if (!readStringData(origin)) {
2710 fail();
2711 return JSValue();
2712 }
2713 CachedStringRef keyedMaterial;
2714 if (!readStringData(keyedMaterial)) {
2715 fail();
2716 return JSValue();
2717 }
2718 unsigned size = 0;
2719 if (!read(size))
2720 return JSValue();
2721
2722 Vector<RTCCertificate::DtlsFingerprint> fingerprints;
2723 fingerprints.reserveInitialCapacity(size);
2724 for (unsigned i = 0; i < size; i++) {
2725 CachedStringRef algorithm;
2726 if (!readStringData(algorithm))
2727 return JSValue();
2728 CachedStringRef value;
2729 if (!readStringData(value))
2730 return JSValue();
2731 fingerprints.uncheckedAppend(RTCCertificate::DtlsFingerprint { algorithm->string(), value->string() });
2732 }
2733
2734 if (!m_isDOMGlobalObject)
2735 return constructEmptyObject(m_exec, m_globalObject->objectPrototype());
2736
2737 auto rtcCertificate = RTCCertificate::create(SecurityOrigin::createFromString(origin->string()), expires, WTFMove(fingerprints), certificate->takeString(), keyedMaterial->takeString());
2738 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), WTFMove(rtcCertificate));
2739 }
2740#endif
2741
2742 JSValue readTerminal()
2743 {
2744 SerializationTag tag = readTag();
2745 switch (tag) {
2746 case UndefinedTag:
2747 return jsUndefined();
2748 case NullTag:
2749 return jsNull();
2750 case IntTag: {
2751 int32_t i;
2752 if (!read(i))
2753 return JSValue();
2754 return jsNumber(i);
2755 }
2756 case ZeroTag:
2757 return jsNumber(0);
2758 case OneTag:
2759 return jsNumber(1);
2760 case FalseTag:
2761 return jsBoolean(false);
2762 case TrueTag:
2763 return jsBoolean(true);
2764 case FalseObjectTag: {
2765 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2766 obj->setInternalValue(m_exec->vm(), jsBoolean(false));
2767 m_gcBuffer.appendWithCrashOnOverflow(obj);
2768 return obj;
2769 }
2770 case TrueObjectTag: {
2771 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2772 obj->setInternalValue(m_exec->vm(), jsBoolean(true));
2773 m_gcBuffer.appendWithCrashOnOverflow(obj);
2774 return obj;
2775 }
2776 case DoubleTag: {
2777 double d;
2778 if (!read(d))
2779 return JSValue();
2780 return jsNumber(d);
2781 }
2782 case NumberObjectTag: {
2783 double d;
2784 if (!read(d))
2785 return JSValue();
2786 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
2787 m_gcBuffer.appendWithCrashOnOverflow(obj);
2788 return obj;
2789 }
2790 case DateTag: {
2791 double d;
2792 if (!read(d))
2793 return JSValue();
2794 return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
2795 }
2796 case FileTag: {
2797 RefPtr<File> file;
2798 if (!readFile(file))
2799 return JSValue();
2800 if (!m_isDOMGlobalObject)
2801 return jsNull();
2802 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
2803 }
2804 case FileListTag: {
2805 unsigned length = 0;
2806 if (!read(length))
2807 return JSValue();
2808 Vector<Ref<File>> files;
2809 for (unsigned i = 0; i < length; i++) {
2810 RefPtr<File> file;
2811 if (!readFile(file))
2812 return JSValue();
2813 if (m_isDOMGlobalObject)
2814 files.append(file.releaseNonNull());
2815 }
2816 if (!m_isDOMGlobalObject)
2817 return jsNull();
2818 return getJSValue(FileList::create(WTFMove(files)).get());
2819 }
2820 case ImageDataTag: {
2821 uint32_t width;
2822 if (!read(width))
2823 return JSValue();
2824 uint32_t height;
2825 if (!read(height))
2826 return JSValue();
2827 uint32_t length;
2828 if (!read(length))
2829 return JSValue();
2830 if (static_cast<uint32_t>(m_end - m_ptr) < length) {
2831 fail();
2832 return JSValue();
2833 }
2834 if (!m_isDOMGlobalObject) {
2835 m_ptr += length;
2836 return jsNull();
2837 }
2838 IntSize imageSize(width, height);
2839 RELEASE_ASSERT(!length || (imageSize.area() * 4).unsafeGet() <= length);
2840 auto result = ImageData::create(imageSize);
2841 if (!result) {
2842 fail();
2843 return JSValue();
2844 }
2845 if (length)
2846 memcpy(result->data()->data(), m_ptr, length);
2847 else
2848 result->data()->zeroFill();
2849 m_ptr += length;
2850 return getJSValue(result.get());
2851 }
2852 case BlobTag: {
2853 CachedStringRef url;
2854 if (!readStringData(url))
2855 return JSValue();
2856 CachedStringRef type;
2857 if (!readStringData(type))
2858 return JSValue();
2859 unsigned long long size = 0;
2860 if (!read(size))
2861 return JSValue();
2862 if (!m_isDOMGlobalObject)
2863 return jsNull();
2864 return getJSValue(Blob::deserialize(URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get());
2865 }
2866 case StringTag: {
2867 CachedStringRef cachedString;
2868 if (!readStringData(cachedString))
2869 return JSValue();
2870 return cachedString->jsString(m_exec);
2871 }
2872 case EmptyStringTag:
2873 return jsEmptyString(&m_exec->vm());
2874 case StringObjectTag: {
2875 CachedStringRef cachedString;
2876 if (!readStringData(cachedString))
2877 return JSValue();
2878 StringObject* obj = constructString(m_exec->vm(), m_globalObject, cachedString->jsString(m_exec));
2879 m_gcBuffer.appendWithCrashOnOverflow(obj);
2880 return obj;
2881 }
2882 case EmptyStringObjectTag: {
2883 VM& vm = m_exec->vm();
2884 StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(&vm));
2885 m_gcBuffer.appendWithCrashOnOverflow(obj);
2886 return obj;
2887 }
2888 case RegExpTag: {
2889 CachedStringRef pattern;
2890 if (!readStringData(pattern))
2891 return JSValue();
2892 CachedStringRef flags;
2893 if (!readStringData(flags))
2894 return JSValue();
2895 auto reFlags = Yarr::parseFlags(flags->string());
2896 ASSERT(reFlags.hasValue());
2897 VM& vm = m_exec->vm();
2898 RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
2899 return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
2900 }
2901 case ObjectReferenceTag: {
2902 unsigned index = 0;
2903 if (!readConstantPoolIndex(m_gcBuffer, index)) {
2904 fail();
2905 return JSValue();
2906 }
2907 return m_gcBuffer.at(index);
2908 }
2909 case MessagePortReferenceTag: {
2910 uint32_t index;
2911 bool indexSuccessfullyRead = read(index);
2912 if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
2913 fail();
2914 return JSValue();
2915 }
2916 return getJSValue(m_messagePorts[index].get());
2917 }
2918#if ENABLE(WEBASSEMBLY)
2919 case WasmModuleTag: {
2920 uint32_t index;
2921 bool indexSuccessfullyRead = read(index);
2922 if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) {
2923 fail();
2924 return JSValue();
2925 }
2926 auto scope = DECLARE_THROW_SCOPE(m_exec->vm());
2927 JSValue result = JSC::JSWebAssemblyModule::createStub(m_exec->vm(), m_exec, m_globalObject->webAssemblyModuleStructure(), m_wasmModules->at(index));
2928 // Since we are cloning a JSWebAssemblyModule, it's impossible for that
2929 // module to not have been a valid module. Therefore, createStub should
2930 // not trow.
2931 scope.releaseAssertNoException();
2932 m_gcBuffer.appendWithCrashOnOverflow(result);
2933 return result;
2934 }
2935#endif
2936 case ArrayBufferTag: {
2937 RefPtr<ArrayBuffer> arrayBuffer;
2938 if (!readArrayBuffer(arrayBuffer)) {
2939 fail();
2940 return JSValue();
2941 }
2942 Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
2943 // A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
2944 // array buffers while the sender is. In that case, we would see a null structure here.
2945 if (!structure) {
2946 fail();
2947 return JSValue();
2948 }
2949 JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer));
2950 m_gcBuffer.appendWithCrashOnOverflow(result);
2951 return result;
2952 }
2953 case ArrayBufferTransferTag: {
2954 uint32_t index;
2955 bool indexSuccessfullyRead = read(index);
2956 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
2957 fail();
2958 return JSValue();
2959 }
2960
2961 if (!m_arrayBuffers[index])
2962 m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
2963
2964 return getJSValue(m_arrayBuffers[index].get());
2965 }
2966 case SharedArrayBufferTag: {
2967 uint32_t index = UINT_MAX;
2968 bool indexSuccessfullyRead = read(index);
2969 if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) {
2970 fail();
2971 return JSValue();
2972 }
2973
2974 RELEASE_ASSERT(m_sharedBuffers->at(index));
2975 auto buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index)));
2976 JSValue result = getJSValue(buffer.get());
2977 m_gcBuffer.appendWithCrashOnOverflow(result);
2978 return result;
2979 }
2980 case ArrayBufferViewTag: {
2981 JSValue arrayBufferView;
2982 if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) {
2983 fail();
2984 return JSValue();
2985 }
2986 m_gcBuffer.appendWithCrashOnOverflow(arrayBufferView);
2987 return arrayBufferView;
2988 }
2989#if ENABLE(WEB_CRYPTO)
2990 case CryptoKeyTag: {
2991 Vector<uint8_t> wrappedKey;
2992 if (!read(wrappedKey)) {
2993 fail();
2994 return JSValue();
2995 }
2996 Vector<uint8_t> serializedKey;
2997 if (!unwrapCryptoKey(m_exec, wrappedKey, serializedKey)) {
2998 fail();
2999 return JSValue();
3000 }
3001 JSValue cryptoKey;
3002 Vector<RefPtr<MessagePort>> dummyMessagePorts;
3003 CloneDeserializer rawKeyDeserializer(m_exec, m_globalObject, dummyMessagePorts, nullptr, { },
3004#if ENABLE(WEBASSEMBLY)
3005 nullptr,
3006#endif
3007 serializedKey);
3008 if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
3009 fail();
3010 return JSValue();
3011 }
3012 m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
3013 return cryptoKey;
3014 }
3015#endif
3016 case DOMPointReadOnlyTag:
3017 return readDOMPoint<DOMPointReadOnly>();
3018 case DOMPointTag:
3019 return readDOMPoint<DOMPoint>();
3020 case DOMRectReadOnlyTag:
3021 return readDOMRect<DOMRectReadOnly>();
3022 case DOMRectTag:
3023 return readDOMRect<DOMRect>();
3024 case DOMMatrixReadOnlyTag:
3025 return readDOMMatrix<DOMMatrixReadOnly>();
3026 case DOMMatrixTag:
3027 return readDOMMatrix<DOMMatrix>();
3028 case DOMQuadTag:
3029 return readDOMQuad();
3030 case ImageBitmapTransferTag:
3031 return readImageBitmap();
3032#if ENABLE(WEB_RTC)
3033 case RTCCertificateTag:
3034 return readRTCCertificate();
3035
3036#endif
3037 default:
3038 m_ptr--; // Push the tag back
3039 return JSValue();
3040 }
3041 }
3042
3043 template<SerializationTag Tag>
3044 bool consumeCollectionDataTerminationIfPossible()
3045 {
3046 if (readTag() == Tag)
3047 return true;
3048 m_ptr--;
3049 return false;
3050 }
3051
3052 JSGlobalObject* m_globalObject;
3053 bool m_isDOMGlobalObject;
3054 const uint8_t* m_ptr;
3055 const uint8_t* m_end;
3056 unsigned m_version;
3057 Vector<CachedString> m_constantPool;
3058 const Vector<RefPtr<MessagePort>>& m_messagePorts;
3059 ArrayBufferContentsArray* m_arrayBufferContents;
3060 Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers;
3061 Vector<String> m_blobURLs;
3062 PAL::SessionID m_sessionID;
3063 Vector<String> m_blobFilePaths;
3064 ArrayBufferContentsArray* m_sharedBuffers;
3065 Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>> m_imageBuffers;
3066 Vector<RefPtr<ImageBitmap>> m_imageBitmaps;
3067#if ENABLE(WEBASSEMBLY)
3068 WasmModuleArray* m_wasmModules;
3069#endif
3070
3071 String blobFilePathForBlobURL(const String& blobURL)
3072 {
3073 size_t i = 0;
3074 for (; i < m_blobURLs.size(); ++i) {
3075 if (m_blobURLs[i] == blobURL)
3076 break;
3077 }
3078
3079 return i < m_blobURLs.size() ? m_blobFilePaths[i] : String();
3080 }
3081};
3082
3083DeserializationResult CloneDeserializer::deserialize()
3084{
3085 VM& vm = m_exec->vm();
3086 auto scope = DECLARE_THROW_SCOPE(vm);
3087
3088 Vector<uint32_t, 16> indexStack;
3089 Vector<Identifier, 16> propertyNameStack;
3090 Vector<JSObject*, 32> outputObjectStack;
3091 Vector<JSValue, 4> mapKeyStack;
3092 Vector<JSMap*, 4> mapStack;
3093 Vector<JSSet*, 4> setStack;
3094 Vector<WalkerState, 16> stateStack;
3095 WalkerState state = StateUnknown;
3096 JSValue outValue;
3097
3098 while (1) {
3099 switch (state) {
3100 arrayStartState:
3101 case ArrayStartState: {
3102 uint32_t length;
3103 if (!read(length)) {
3104 fail();
3105 goto error;
3106 }
3107 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
3108 if (UNLIKELY(scope.exception()))
3109 goto error;
3110 m_gcBuffer.appendWithCrashOnOverflow(outArray);
3111 outputObjectStack.append(outArray);
3112 }
3113 arrayStartVisitMember:
3114 FALLTHROUGH;
3115 case ArrayStartVisitMember: {
3116 uint32_t index;
3117 if (!read(index)) {
3118 fail();
3119 goto error;
3120 }
3121 if (index == TerminatorTag) {
3122 JSObject* outArray = outputObjectStack.last();
3123 outValue = outArray;
3124 outputObjectStack.removeLast();
3125 break;
3126 } else if (index == NonIndexPropertiesTag) {
3127 goto objectStartVisitMember;
3128 }
3129
3130 if (JSValue terminal = readTerminal()) {
3131 putProperty(outputObjectStack.last(), index, terminal);
3132 goto arrayStartVisitMember;
3133 }
3134 if (m_failed)
3135 goto error;
3136 indexStack.append(index);
3137 stateStack.append(ArrayEndVisitMember);
3138 goto stateUnknown;
3139 }
3140 case ArrayEndVisitMember: {
3141 JSObject* outArray = outputObjectStack.last();
3142 putProperty(outArray, indexStack.last(), outValue);
3143 indexStack.removeLast();
3144 goto arrayStartVisitMember;
3145 }
3146 objectStartState:
3147 case ObjectStartState: {
3148 if (outputObjectStack.size() > maximumFilterRecursion)
3149 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3150 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
3151 m_gcBuffer.appendWithCrashOnOverflow(outObject);
3152 outputObjectStack.append(outObject);
3153 }
3154 objectStartVisitMember:
3155 FALLTHROUGH;
3156 case ObjectStartVisitMember: {
3157 CachedStringRef cachedString;
3158 bool wasTerminator = false;
3159 if (!readStringData(cachedString, wasTerminator)) {
3160 if (!wasTerminator)
3161 goto error;
3162
3163 JSObject* outObject = outputObjectStack.last();
3164 outValue = outObject;
3165 outputObjectStack.removeLast();
3166 break;
3167 }
3168
3169 if (JSValue terminal = readTerminal()) {
3170 putProperty(outputObjectStack.last(), Identifier::fromString(m_exec, cachedString->string()), terminal);
3171 goto objectStartVisitMember;
3172 }
3173 stateStack.append(ObjectEndVisitMember);
3174 propertyNameStack.append(Identifier::fromString(m_exec, cachedString->string()));
3175 goto stateUnknown;
3176 }
3177 case ObjectEndVisitMember: {
3178 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
3179 propertyNameStack.removeLast();
3180 goto objectStartVisitMember;
3181 }
3182 mapObjectStartState: {
3183 if (outputObjectStack.size() > maximumFilterRecursion)
3184 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3185 JSMap* map = JSMap::create(m_exec, m_exec->vm(), m_globalObject->mapStructure());
3186 if (UNLIKELY(scope.exception()))
3187 goto error;
3188 m_gcBuffer.appendWithCrashOnOverflow(map);
3189 outputObjectStack.append(map);
3190 mapStack.append(map);
3191 goto mapDataStartVisitEntry;
3192 }
3193 mapDataStartVisitEntry:
3194 case MapDataStartVisitEntry: {
3195 if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) {
3196 mapStack.removeLast();
3197 goto objectStartVisitMember;
3198 }
3199 stateStack.append(MapDataEndVisitKey);
3200 goto stateUnknown;
3201 }
3202 case MapDataEndVisitKey: {
3203 mapKeyStack.append(outValue);
3204 stateStack.append(MapDataEndVisitValue);
3205 goto stateUnknown;
3206 }
3207 case MapDataEndVisitValue: {
3208 mapStack.last()->set(m_exec, mapKeyStack.last(), outValue);
3209 mapKeyStack.removeLast();
3210 goto mapDataStartVisitEntry;
3211 }
3212
3213 setObjectStartState: {
3214 if (outputObjectStack.size() > maximumFilterRecursion)
3215 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3216 JSSet* set = JSSet::create(m_exec, m_exec->vm(), m_globalObject->setStructure());
3217 if (UNLIKELY(scope.exception()))
3218 goto error;
3219 m_gcBuffer.appendWithCrashOnOverflow(set);
3220 outputObjectStack.append(set);
3221 setStack.append(set);
3222 goto setDataStartVisitEntry;
3223 }
3224 setDataStartVisitEntry:
3225 case SetDataStartVisitEntry: {
3226 if (consumeCollectionDataTerminationIfPossible<NonSetPropertiesTag>()) {
3227 setStack.removeLast();
3228 goto objectStartVisitMember;
3229 }
3230 stateStack.append(SetDataEndVisitKey);
3231 goto stateUnknown;
3232 }
3233 case SetDataEndVisitKey: {
3234 JSSet* set = setStack.last();
3235 set->add(m_exec, outValue);
3236 goto setDataStartVisitEntry;
3237 }
3238
3239 stateUnknown:
3240 case StateUnknown:
3241 if (JSValue terminal = readTerminal()) {
3242 outValue = terminal;
3243 break;
3244 }
3245 SerializationTag tag = readTag();
3246 if (tag == ArrayTag)
3247 goto arrayStartState;
3248 if (tag == ObjectTag)
3249 goto objectStartState;
3250 if (tag == MapObjectTag)
3251 goto mapObjectStartState;
3252 if (tag == SetObjectTag)
3253 goto setObjectStartState;
3254 goto error;
3255 }
3256 if (stateStack.isEmpty())
3257 break;
3258
3259 state = stateStack.last();
3260 stateStack.removeLast();
3261 }
3262 ASSERT(outValue);
3263 ASSERT(!m_failed);
3264 return std::make_pair(outValue, SerializationReturnCode::SuccessfullyCompleted);
3265error:
3266 fail();
3267 return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
3268}
3269
3270SerializedScriptValue::~SerializedScriptValue() = default;
3271
3272SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer)
3273 : m_data(WTFMove(buffer))
3274{
3275}
3276
3277SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray)
3278 : m_data(WTFMove(buffer))
3279 , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray))
3280{
3281}
3282
3283SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray, std::unique_ptr<ArrayBufferContentsArray> sharedBufferContentsArray, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers
3284#if ENABLE(WEBASSEMBLY)
3285 , std::unique_ptr<WasmModuleArray> wasmModulesArray
3286#endif
3287 )
3288 : m_data(WTFMove(buffer))
3289 , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray))
3290 , m_sharedBufferContentsArray(WTFMove(sharedBufferContentsArray))
3291 , m_imageBuffers(WTFMove(imageBuffers))
3292#if ENABLE(WEBASSEMBLY)
3293 , m_wasmModulesArray(WTFMove(wasmModulesArray))
3294#endif
3295 , m_sessionID(sessionID)
3296{
3297 // Since this SerializedScriptValue is meant to be passed between threads, its String data members
3298 // need to be isolatedCopies so we don't run into thread safety issues for the StringImpls.
3299 m_blobURLs.reserveInitialCapacity(blobURLs.size());
3300 for (auto& url : blobURLs)
3301 m_blobURLs.uncheckedAppend(url.isolatedCopy());
3302}
3303
3304static ExceptionOr<std::unique_ptr<ArrayBufferContentsArray>> transferArrayBuffers(VM& vm, const Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers)
3305{
3306 if (arrayBuffers.isEmpty())
3307 return nullptr;
3308
3309 auto contents = std::make_unique<ArrayBufferContentsArray>(arrayBuffers.size());
3310
3311 HashSet<JSC::ArrayBuffer*> visited;
3312 for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
3313 if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
3314 continue;
3315 visited.add(arrayBuffers[arrayBufferIndex].get());
3316
3317 bool result = arrayBuffers[arrayBufferIndex]->transferTo(vm, contents->at(arrayBufferIndex));
3318 if (!result)
3319 return Exception { TypeError };
3320 }
3321
3322 return contents;
3323}
3324
3325static void maybeThrowExceptionIfSerializationFailed(ExecState& state, SerializationReturnCode code)
3326{
3327 auto& vm = state.vm();
3328 auto scope = DECLARE_THROW_SCOPE(vm);
3329
3330 switch (code) {
3331 case SerializationReturnCode::SuccessfullyCompleted:
3332 break;
3333 case SerializationReturnCode::StackOverflowError:
3334 throwException(&state, scope, createStackOverflowError(&state));
3335 break;
3336 case SerializationReturnCode::ValidationError:
3337 throwTypeError(&state, scope, "Unable to deserialize data."_s);
3338 break;
3339 case SerializationReturnCode::DataCloneError:
3340 throwDataCloneError(state, scope);
3341 break;
3342 case SerializationReturnCode::ExistingExceptionError:
3343 case SerializationReturnCode::UnspecifiedError:
3344 break;
3345 case SerializationReturnCode::InterruptedExecutionError:
3346 ASSERT_NOT_REACHED();
3347 }
3348}
3349
3350static Exception exceptionForSerializationFailure(SerializationReturnCode code)
3351{
3352 ASSERT(code != SerializationReturnCode::SuccessfullyCompleted);
3353
3354 switch (code) {
3355 case SerializationReturnCode::StackOverflowError:
3356 return Exception { StackOverflowError };
3357 case SerializationReturnCode::ValidationError:
3358 return Exception { TypeError };
3359 case SerializationReturnCode::DataCloneError:
3360 return Exception { DataCloneError };
3361 case SerializationReturnCode::ExistingExceptionError:
3362 return Exception { ExistingExceptionError };
3363 case SerializationReturnCode::UnspecifiedError:
3364 return Exception { TypeError };
3365 case SerializationReturnCode::SuccessfullyCompleted:
3366 case SerializationReturnCode::InterruptedExecutionError:
3367 ASSERT_NOT_REACHED();
3368 return Exception { TypeError };
3369 }
3370 ASSERT_NOT_REACHED();
3371 return Exception { TypeError };
3372}
3373
3374RefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState& exec, JSValue value, SerializationErrorMode throwExceptions)
3375{
3376 Vector<uint8_t> buffer;
3377 Vector<String> blobURLs;
3378 PAL::SessionID sessionID;
3379 Vector<RefPtr<MessagePort>> dummyMessagePorts;
3380 Vector<RefPtr<ImageBitmap>> dummyImageBitmaps;
3381 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
3382#if ENABLE(WEBASSEMBLY)
3383 WasmModuleArray dummyModules;
3384#endif
3385 ArrayBufferContentsArray dummySharedBuffers;
3386 auto code = CloneSerializer::serialize(&exec, value, dummyMessagePorts, dummyArrayBuffers, dummyImageBitmaps,
3387#if ENABLE(WEBASSEMBLY)
3388 dummyModules,
3389#endif
3390 blobURLs, sessionID, buffer, SerializationContext::Default, dummySharedBuffers);
3391
3392#if ENABLE(WEBASSEMBLY)
3393 ASSERT_WITH_MESSAGE(dummyModules.isEmpty(), "Wasm::Module serialization is only allowed in the postMessage context");
3394#endif
3395
3396 if (throwExceptions == SerializationErrorMode::Throwing)
3397 maybeThrowExceptionIfSerializationFailed(exec, code);
3398
3399 if (code != SerializationReturnCode::SuccessfullyCompleted)
3400 return nullptr;
3401
3402 return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, sessionID, nullptr, nullptr, { }
3403#if ENABLE(WEBASSEMBLY)
3404 , nullptr
3405#endif
3406 ));
3407}
3408
3409static bool containsDuplicates(const Vector<RefPtr<ImageBitmap>>& imageBitmaps)
3410{
3411 HashSet<ImageBitmap*> visited;
3412 for (auto& imageBitmap : imageBitmaps) {
3413 if (!visited.add(imageBitmap.get()))
3414 return true;
3415 }
3416 return false;
3417}
3418
3419ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState& state, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationContext context)
3420{
3421 VM& vm = state.vm();
3422 Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
3423 Vector<RefPtr<ImageBitmap>> imageBitmaps;
3424 for (auto& transferable : transferList) {
3425 if (auto arrayBuffer = toPossiblySharedArrayBuffer(vm, transferable.get())) {
3426 if (arrayBuffer->isNeutered())
3427 return Exception { DataCloneError };
3428 if (arrayBuffer->isLocked()) {
3429 auto scope = DECLARE_THROW_SCOPE(vm);
3430 throwVMTypeError(&state, scope, errorMesasgeForTransfer(arrayBuffer));
3431 return Exception { ExistingExceptionError };
3432 }
3433 arrayBuffers.append(WTFMove(arrayBuffer));
3434 continue;
3435 }
3436 if (auto port = JSMessagePort::toWrapped(vm, transferable.get())) {
3437 // FIXME: This should check if the port is detached as per https://html.spec.whatwg.org/multipage/infrastructure.html#istransferable.
3438 messagePorts.append(WTFMove(port));
3439 continue;
3440 }
3441
3442 if (auto imageBitmap = JSImageBitmap::toWrapped(vm, transferable.get())) {
3443 if (imageBitmap->isDetached())
3444 return Exception { DataCloneError };
3445
3446 imageBitmaps.append(WTFMove(imageBitmap));
3447 continue;
3448 }
3449
3450 return Exception { DataCloneError };
3451 }
3452
3453 if (containsDuplicates(imageBitmaps))
3454 return Exception { DataCloneError };
3455
3456 Vector<uint8_t> buffer;
3457 Vector<String> blobURLs;
3458 PAL::SessionID sessionID;
3459#if ENABLE(WEBASSEMBLY)
3460 WasmModuleArray wasmModules;
3461#endif
3462 std::unique_ptr<ArrayBufferContentsArray> sharedBuffers = std::make_unique<ArrayBufferContentsArray>();
3463 auto code = CloneSerializer::serialize(&state, value, messagePorts, arrayBuffers, imageBitmaps,
3464#if ENABLE(WEBASSEMBLY)
3465 wasmModules,
3466#endif
3467 blobURLs, sessionID, buffer, context, *sharedBuffers);
3468
3469 if (code != SerializationReturnCode::SuccessfullyCompleted)
3470 return exceptionForSerializationFailure(code);
3471
3472 auto arrayBufferContentsArray = transferArrayBuffers(vm, arrayBuffers);
3473 if (arrayBufferContentsArray.hasException())
3474 return arrayBufferContentsArray.releaseException();
3475
3476 auto imageBuffers = ImageBitmap::detachBitmaps(WTFMove(imageBitmaps));
3477
3478 return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, sessionID, arrayBufferContentsArray.releaseReturnValue(), context == SerializationContext::WorkerPostMessage ? WTFMove(sharedBuffers) : nullptr, WTFMove(imageBuffers)
3479#if ENABLE(WEBASSEMBLY)
3480 , std::make_unique<WasmModuleArray>(wasmModules)
3481#endif
3482 ));
3483}
3484
3485RefPtr<SerializedScriptValue> SerializedScriptValue::create(StringView string)
3486{
3487 Vector<uint8_t> buffer;
3488 if (!CloneSerializer::serialize(string, buffer))
3489 return nullptr;
3490 return adoptRef(*new SerializedScriptValue(WTFMove(buffer)));
3491}
3492
3493RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
3494{
3495 ExecState* exec = toJS(originContext);
3496 VM& vm = exec->vm();
3497 JSLockHolder locker(vm);
3498 auto scope = DECLARE_CATCH_SCOPE(vm);
3499
3500 JSValue value = toJS(exec, apiValue);
3501 auto serializedValue = SerializedScriptValue::create(*exec, value);
3502 if (UNLIKELY(scope.exception())) {
3503 if (exception)
3504 *exception = toRef(exec, scope.exception()->value());
3505 scope.clearException();
3506 return nullptr;
3507 }
3508 ASSERT(serializedValue);
3509 return serializedValue;
3510}
3511
3512String SerializedScriptValue::toString()
3513{
3514 return CloneDeserializer::deserializeString(m_data);
3515}
3516
3517JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions)
3518{
3519 return deserialize(exec, globalObject, { }, throwExceptions);
3520}
3521
3522JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, SerializationErrorMode throwExceptions)
3523{
3524 Vector<String> dummyBlobs;
3525 Vector<String> dummyPaths;
3526 PAL::SessionID dummySessionID;
3527 return deserialize(exec, globalObject, messagePorts, dummyBlobs, dummySessionID, dummyPaths, throwExceptions);
3528}
3529
3530JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions)
3531{
3532 DeserializationResult result = CloneDeserializer::deserialize(&exec, globalObject, messagePorts, WTFMove(m_imageBuffers), m_arrayBufferContentsArray.get(), m_data, blobURLs, sessionID, blobFilePaths, m_sharedBufferContentsArray.get()
3533#if ENABLE(WEBASSEMBLY)
3534 , m_wasmModulesArray.get()
3535#endif
3536 );
3537 if (throwExceptions == SerializationErrorMode::Throwing)
3538 maybeThrowExceptionIfSerializationFailed(exec, result.second);
3539 return result.first ? result.first : jsNull();
3540}
3541
3542JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
3543{
3544 ExecState* exec = toJS(destinationContext);
3545 VM& vm = exec->vm();
3546 JSLockHolder locker(vm);
3547 auto scope = DECLARE_CATCH_SCOPE(vm);
3548
3549 JSValue value = deserialize(*exec, exec->lexicalGlobalObject());
3550 if (UNLIKELY(scope.exception())) {
3551 if (exception)
3552 *exception = toRef(exec, scope.exception()->value());
3553 scope.clearException();
3554 return nullptr;
3555 }
3556 ASSERT(value);
3557 return toRef(exec, value);
3558}
3559
3560Ref<SerializedScriptValue> SerializedScriptValue::nullValue()
3561{
3562 return adoptRef(*new SerializedScriptValue(Vector<uint8_t>()));
3563}
3564
3565uint32_t SerializedScriptValue::wireFormatVersion()
3566{
3567 return CurrentVersion;
3568}
3569
3570#if ENABLE(INDEXED_DATABASE)
3571Vector<String> SerializedScriptValue::blobURLsIsolatedCopy() const
3572{
3573 Vector<String> result;
3574 result.reserveInitialCapacity(m_blobURLs.size());
3575 for (auto& url : m_blobURLs)
3576 result.uncheckedAppend(url.isolatedCopy());
3577
3578 return result;
3579}
3580
3581void SerializedScriptValue::writeBlobsToDiskForIndexedDB(CompletionHandler<void(IDBValue&&)>&& completionHandler)
3582{
3583 ASSERT(isMainThread());
3584 ASSERT(hasBlobURLs());
3585
3586 // FIXME: Add m_sessionID as a parameter here.
3587 blobRegistry().writeBlobsToTemporaryFiles(m_blobURLs, [completionHandler = WTFMove(completionHandler), this, protectedThis = makeRef(*this)] (auto&& blobFilePaths) mutable {
3588 ASSERT(isMainThread());
3589
3590 if (blobFilePaths.isEmpty()) {
3591 // We should have successfully written blobs to temporary files.
3592 // If we failed, then we can't successfully store this record.
3593 completionHandler({ });
3594 return;
3595 }
3596
3597 ASSERT(m_blobURLs.size() == blobFilePaths.size());
3598
3599 completionHandler({ *this, m_blobURLs, m_sessionID, blobFilePaths });
3600 });
3601}
3602
3603IDBValue SerializedScriptValue::writeBlobsToDiskForIndexedDBSynchronously()
3604{
3605 ASSERT(!isMainThread());
3606
3607 IDBValue value;
3608 Lock lock;
3609 Condition condition;
3610 lock.lock();
3611
3612 RunLoop::main().dispatch([this, conditionPtr = &condition, valuePtr = &value] {
3613 writeBlobsToDiskForIndexedDB([conditionPtr, valuePtr](IDBValue&& result) {
3614 ASSERT(isMainThread());
3615 valuePtr->setAsIsolatedCopy(result);
3616
3617 conditionPtr->notifyAll();
3618 });
3619 });
3620
3621 condition.wait(lock);
3622
3623 return value;
3624}
3625
3626#endif // ENABLE(INDEXED_DATABASE)
3627
3628} // namespace WebCore
3629