From 84ac6a454f153eb63d227a1c3cf89bb566ead1e3 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 12 Dec 2023 13:30:16 -0700 Subject: [PATCH] LibWeb: Use ``Vector>`` in transfer variants of serialize Also trap the invalid object index inserted for transferred values in deserialization. In the future we should avoid inserting that placeholder value in the data stream at all. --- .../LibWeb/HTML/StructuredSerialize.cpp | 25 +++++++++++-------- .../LibWeb/HTML/StructuredSerialize.h | 4 +-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp index b08ae90b68..2d5a4fe682 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp @@ -578,6 +578,10 @@ public: // 2. If memory[serialized] exists, then return memory[serialized]. if (tag == ValueTag::ObjectReference) { auto index = m_serialized[m_position++]; + // FIXME: For transferred items, find a way to avoid putting placeholders in the serialized data + if (index == NumericLimits::max()) { + return JS::js_null(); + } return m_memory[index]; } @@ -921,7 +925,7 @@ private: }; // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializewithtransfer -WebIDL::ExceptionOr structured_serialize_with_transfer(JS::VM& vm, JS::Value value, JS::MarkedVector transfer_list) +WebIDL::ExceptionOr structured_serialize_with_transfer(JS::VM& vm, JS::Value value, Vector> const& transfer_list) { // 1. Let memory be an empty map. SerializationMemory memory = {}; @@ -931,19 +935,20 @@ WebIDL::ExceptionOr structured_serialize_with_transfer // 1. If transferable has neither an [[ArrayBufferData]] internal slot nor a [[Detached]] internal slot, then throw a "DataCloneError" DOMException. // FIXME: Handle transferring ArrayBufferData objects - if (!transferable.is_object() || !is(transferable.as_object())) { + if (!is(*transferable)) { return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot transfer type"_fly_string); } // FIXME: 2. If transferable has an [[ArrayBufferData]] internal slot and IsSharedArrayBuffer(transferable) is true, then throw a "DataCloneError" DOMException. // 3. If memory[transferable] exists, then throw a "DataCloneError" DOMException. - if (memory.contains(transferable)) { + auto transferable_value = JS::Value(transferable.ptr()); + if (memory.contains(transferable_value)) { return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot transfer value twice"_fly_string); } // 4. Set memory[transferable] to { [[Type]]: an uninitialized value }. - memory.set(JS::make_handle(transferable), NumericLimits::max()); + memory.set(JS::make_handle(transferable_value), NumericLimits::max()); } // 3. Let serialized be ? StructuredSerializeInternal(value, false, memory). @@ -958,8 +963,8 @@ WebIDL::ExceptionOr structured_serialize_with_transfer // 1. FIXME: If transferable has an [[ArrayBufferData]] internal slot and IsDetachedBuffer(transferable) is true, then throw a "DataCloneError" DOMException. // 2. If transferable has a [[Detached]] internal slot and transferable.[[Detached]] is true, then throw a "DataCloneError" DOMException. - if (transferable.is_object() && is(transferable.as_object())) { - auto& transferable_object = dynamic_cast(transferable.as_object()); + if (is(*transferable)) { + auto& transferable_object = dynamic_cast(*transferable); if (transferable_object.is_detached()) { return WebIDL::DataCloneError::create(*vm.current_realm(), "Value already transferred"_fly_string); } @@ -976,8 +981,8 @@ WebIDL::ExceptionOr structured_serialize_with_transfer // 5. Otherwise: else { // 1. Assert: transferable is a platform object that is a transferable object. - auto& transferable_object = dynamic_cast(transferable.as_object()); - VERIFY(is(transferable.as_object())); + auto& transferable_object = dynamic_cast(*transferable); + VERIFY(is(*transferable)); // 2. Let interfaceName be the identifier of the primary interface of transferable. auto interface_name = transferable_object.primary_interface(); @@ -1035,7 +1040,7 @@ WebIDL::ExceptionOr structured_deserialize_with_tran auto memory = DeserializationMemory(vm.heap()); // 2. Let transferredValues be a new empty List. - auto transferred_values = JS::MarkedVector(vm.heap()); + Vector> transferred_values; // 3. For each transferDataHolder of serializeWithTransferResult.[[TransferDataHolders]]: for (auto& transfer_data_holder : serialize_with_transfer_result.transfer_data_holders) { @@ -1078,7 +1083,7 @@ WebIDL::ExceptionOr structured_deserialize_with_tran memory.append(value); // 6. Append value to transferredValues. - transferred_values.append(value); + transferred_values.append(JS::make_handle(value.as_object())); } // 4. Let deserialized be ? StructuredDeserialize(serializeWithTransferResult.[[Serialized]], targetRealm, memory). diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h index eefde90fc9..3afe51b313 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h @@ -37,7 +37,7 @@ struct SerializedTransferRecord { struct DeserializedTransferRecord { JS::Value deserialized; - JS::MarkedVector transferred_values; + Vector> transferred_values; }; enum class TransferType : u8 { @@ -50,7 +50,7 @@ WebIDL::ExceptionOr structured_serialize_internal(JS::VM& v WebIDL::ExceptionOr structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional); -WebIDL::ExceptionOr structured_serialize_with_transfer(JS::VM& vm, JS::Value value, JS::MarkedVector transfer_list); +WebIDL::ExceptionOr structured_serialize_with_transfer(JS::VM& vm, JS::Value value, Vector> const& transfer_list); WebIDL::ExceptionOr structured_deserialize_with_transfer(JS::VM& vm, SerializedTransferRecord const&); }