From 433a461044730ed2586c9a94510ada88316c87f3 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 3 Sep 2025 08:06:14 -0400 Subject: [PATCH] indexeddb: Serialize all cloned values when storing data. (#39081) We were performing a structured clone but throwing away any serializable DOM interfaces included in the result. We need to instead serialize the full structured clone result so we can deserialize the DOM interfaces when getting the data out of the object store. Testing: Existing WPT coverage is sufficient. Fixes: #38818 Fixed: #38842 Signed-off-by: Josh Matthews --- components/script/dom/idbobjectstore.rs | 7 +++++-- components/script/dom/idbrequest.rs | 15 +++++++-------- .../IndexedDB/blob-valid-after-abort.any.js.ini | 4 ++-- .../blob-valid-after-deletion.any.js.ini | 4 ++-- .../IndexedDB/blob-valid-before-commit.any.js.ini | 10 ---------- .../transaction-deactivation-timing.any.js.ini | 3 --- 6 files changed, 16 insertions(+), 27 deletions(-) delete mode 100644 tests/wpt/meta/IndexedDB/blob-valid-before-commit.any.js.ini diff --git a/components/script/dom/idbobjectstore.rs b/components/script/dom/idbobjectstore.rs index cc6566399d2..a63fcc78333 100644 --- a/components/script/dom/idbobjectstore.rs +++ b/components/script/dom/idbobjectstore.rs @@ -257,7 +257,10 @@ impl IDBObjectStore { } // Step 10. Let clone be a clone of value in targetRealm during transaction. Rethrow any exceptions. - let serialized_value = structuredclone::write(cx, value, None)?; + let cloned_value = structuredclone::write(cx, value, None)?; + let Ok(serialized_value) = bincode::serialize(&cloned_value) else { + return Err(Error::InvalidState); + }; let (sender, receiver) = indexed_db::create_channel(self.global()); @@ -268,7 +271,7 @@ impl IDBObjectStore { AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem { sender, key: serialized_key, - value: serialized_value.serialized, + value: serialized_value, should_overwrite: overwrite, }), receiver, diff --git a/components/script/dom/idbrequest.rs b/components/script/dom/idbrequest.rs index 42e75151b64..cec15a4e1c8 100644 --- a/components/script/dom/idbrequest.rs +++ b/components/script/dom/idbrequest.rs @@ -4,7 +4,6 @@ use std::cell::Cell; -use constellation_traits::StructuredSerializedData; use dom_struct::dom_struct; use ipc_channel::router::ROUTER; use js::jsapi::Heap; @@ -117,14 +116,14 @@ impl RequestListener { key_type_to_jsval(GlobalScope::get_cx(), &key, answer.handle_mut()) }, IdbResult::Data(serialized_data) => { - let data = StructuredSerializedData { - serialized: serialized_data, - ..Default::default() - }; - - if structuredclone::read(&global, data, answer.handle_mut()).is_err() { + let result = bincode::deserialize(&serialized_data) + .map_err(|_| Error::Data) + .and_then(|data| structuredclone::read(&global, data, answer.handle_mut())); + if let Err(e) = result { warn!("Error reading structuredclone data"); - } + Self::handle_async_request_error(&global, cx, request, e); + return; + }; }, IdbResult::Count(count) => { answer.handle_mut().set(DoubleValue(count as f64)); diff --git a/tests/wpt/meta/IndexedDB/blob-valid-after-abort.any.js.ini b/tests/wpt/meta/IndexedDB/blob-valid-after-abort.any.js.ini index 47920aae648..7aae36eab3d 100644 --- a/tests/wpt/meta/IndexedDB/blob-valid-after-abort.any.js.ini +++ b/tests/wpt/meta/IndexedDB/blob-valid-after-abort.any.js.ini @@ -2,13 +2,13 @@ expected: ERROR [blob-valid-after-abort.any.worker.html] - expected: CRASH + expected: TIMEOUT [A blob can be read back after the transaction that added it was aborted.] expected: TIMEOUT [blob-valid-after-abort.any.html] - expected: CRASH + expected: TIMEOUT [A blob can be read back after the transaction that added it was aborted.] expected: TIMEOUT diff --git a/tests/wpt/meta/IndexedDB/blob-valid-after-deletion.any.js.ini b/tests/wpt/meta/IndexedDB/blob-valid-after-deletion.any.js.ini index fe477ce8a89..23cbff1d07f 100644 --- a/tests/wpt/meta/IndexedDB/blob-valid-after-deletion.any.js.ini +++ b/tests/wpt/meta/IndexedDB/blob-valid-after-deletion.any.js.ini @@ -1,10 +1,10 @@ [blob-valid-after-deletion.any.html] - expected: CRASH + expected: TIMEOUT [Blobs stay alive after their records are deleted.] expected: TIMEOUT [blob-valid-after-deletion.any.worker.html] - expected: CRASH + expected: TIMEOUT [Blobs stay alive after their records are deleted.] expected: TIMEOUT diff --git a/tests/wpt/meta/IndexedDB/blob-valid-before-commit.any.js.ini b/tests/wpt/meta/IndexedDB/blob-valid-before-commit.any.js.ini deleted file mode 100644 index e67dfb09af6..00000000000 --- a/tests/wpt/meta/IndexedDB/blob-valid-before-commit.any.js.ini +++ /dev/null @@ -1,10 +0,0 @@ -[blob-valid-before-commit.any.html] - expected: CRASH - [Blobs can be read back before their records are committed.] - expected: TIMEOUT - - -[blob-valid-before-commit.any.worker.html] - expected: CRASH - [Blobs can be read back before their records are committed.] - expected: TIMEOUT diff --git a/tests/wpt/meta/IndexedDB/transaction-deactivation-timing.any.js.ini b/tests/wpt/meta/IndexedDB/transaction-deactivation-timing.any.js.ini index 7e35d96fb64..e486e532b4e 100644 --- a/tests/wpt/meta/IndexedDB/transaction-deactivation-timing.any.js.ini +++ b/tests/wpt/meta/IndexedDB/transaction-deactivation-timing.any.js.ini @@ -16,9 +16,6 @@ [Deactivation of new transactions happens at end of invocation] expected: FAIL - [New transactions are deactivated before next task] - expected: FAIL - [New transactions from microtask are deactivated before next task] expected: FAIL