js: fix serialization of non-transferable objects (#19351)

This commit is contained in:
Meghan Denny
2025-04-29 17:23:26 -08:00
committed by GitHub
parent 3ea7953474
commit 2a2247bbb6
12 changed files with 186 additions and 42 deletions

View File

@@ -887,7 +887,7 @@ public:
WasmMemoryHandleArray& wasmMemoryHandles,
#endif
Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers,
SerializationForStorage forStorage)
SerializationForStorage forStorage, SerializationForTransfer forTransfer)
{
CloneSerializer serializer(lexicalGlobalObject, messagePorts, arrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
@@ -904,7 +904,7 @@ public:
wasmModules,
wasmMemoryHandles,
#endif
out, context, sharedBuffers, forStorage);
out, context, sharedBuffers, forStorage, forTransfer);
return serializer.serialize(value);
}
@@ -989,7 +989,7 @@ private:
WasmModuleArray& wasmModules,
WasmMemoryHandleArray& wasmMemoryHandles,
#endif
Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers, SerializationForStorage forStorage)
Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers, SerializationForStorage forStorage, SerializationForTransfer forTransfer)
: CloneBase(lexicalGlobalObject)
, m_buffer(out)
, m_emptyIdentifier(Identifier::fromString(lexicalGlobalObject->vm(), emptyString()))
@@ -1004,6 +1004,7 @@ private:
, m_serializedVideoFrames(serializedVideoFrames)
#endif
, m_forStorage(forStorage)
, m_forTransfer(forTransfer)
{
write(CurrentVersion);
fillTransferMap(messagePorts, m_transferredMessagePorts);
@@ -1829,7 +1830,7 @@ private:
dummyModules,
dummyMemoryHandles,
#endif
serializedKey, SerializationContext::Default, dummySharedBuffers, m_forStorage);
serializedKey, SerializationContext::Default, dummySharedBuffers, m_forStorage, m_forTransfer);
rawKeySerializer.write(key);
Vector<uint8_t> wrappedKey;
@@ -1943,6 +1944,11 @@ private:
// write bun types
if (auto _cloneable = StructuredCloneableSerialize::fromJS(value)) {
if (m_forTransfer == SerializationForTransfer::Yes && !SerializedScriptValue::isTransferable(m_lexicalGlobalObject, value)) {
write(ObjectTag);
write(TerminatorTag);
return true;
}
StructuredCloneableSerialize cloneable = WTFMove(_cloneable.value());
write(cloneable.tag);
cloneable.write(this, m_lexicalGlobalObject);
@@ -2526,6 +2532,7 @@ private:
Vector<RefPtr<WebCodecsVideoFrame>>& m_serializedVideoFrames;
#endif
SerializationForStorage m_forStorage;
SerializationForTransfer m_forTransfer;
};
SYSV_ABI void SerializedScriptValue::writeBytesForBun(CloneSerializer* ctx, const uint8_t* data, uint32_t size)
@@ -5681,10 +5688,10 @@ static bool canDetachRTCDataChannels(const Vector<Ref<RTCDataChannel>>& channels
}
#endif
RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::JSGlobalObject& globalObject, JSC::JSValue value, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext serializationContext)
RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::JSGlobalObject& globalObject, JSC::JSValue value, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext serializationContext, SerializationForTransfer forTransfer)
{
Vector<RefPtr<MessagePort>> dummyPorts;
auto result = create(globalObject, value, {}, dummyPorts, forStorage, throwExceptions, serializationContext);
auto result = create(globalObject, value, {}, dummyPorts, forStorage, throwExceptions, serializationContext, forTransfer);
// auto result = create(globalObject, value, {}, forStorage, throwExceptions, serializationContext);
if (result.hasException())
return nullptr;
@@ -5696,13 +5703,13 @@ RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::JSGlobalObject&
// return create(globalObject, value, WTFMove(transferList), messagePorts, forStorage, SerializationErrorMode::NonThrowing, serializationContext);
// }
ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& globalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationContext serializationContext)
ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& globalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationContext serializationContext, SerializationForTransfer forTransfer)
{
return create(globalObject, value, WTFMove(transferList), messagePorts, forStorage, SerializationErrorMode::Throwing, serializationContext);
return create(globalObject, value, WTFMove(transferList), messagePorts, forStorage, SerializationErrorMode::Throwing, serializationContext, forTransfer);
}
// ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context)
ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalObject& lexicalGlobalObject, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationForStorage forStorage, SerializationErrorMode throwExceptions, SerializationContext context, SerializationForTransfer forTransfer)
{
VM& vm = lexicalGlobalObject.vm();
Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
@@ -5828,7 +5835,7 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalOb
wasmModules,
wasmMemoryHandles,
#endif
buffer, context, *sharedBuffers, forStorage);
buffer, context, *sharedBuffers, forStorage, forTransfer);
// Serialize may throw an exception. This code looks weird, but we'll rethrow it
// in maybeThrowExceptionIfSerializationFailed (since that may also throw other
@@ -5843,8 +5850,9 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(JSGlobalOb
return exceptionForSerializationFailure(code);
auto arrayBufferContentsArray = transferArrayBuffers(vm, arrayBuffers);
if (arrayBufferContentsArray.hasException())
if (arrayBufferContentsArray.hasException()) {
return arrayBufferContentsArray.releaseException();
}
// auto backingStores = ImageBitmap::detachBitmaps(WTFMove(imageBitmaps));
@@ -6056,9 +6064,9 @@ JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject,
maybeThrowExceptionIfSerializationFailed(lexicalGlobalObject, result.second);
// Rethrow is a bit simpler here since we don't deal with return codes.
RETURN_IF_EXCEPTION(scope, jsNull());
RETURN_IF_EXCEPTION(scope, {});
return result.first ? result.first : jsNull();
return result.first;
}
// JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions, bool* didFail)
// {