Support optional message for dataclone error (#36308)

- [x] our [DataClone
error](d733abfca0/components/script/dom/bindings/error.rs (L80))
needs to support an optional message
- [x] we need to add support to our DOMException implementation to allow
an optional message to replace the default message
- [x] we need to create a new struct used by both StructuredDataReader
and StructuredDataWriter for storing the error message in the
report_error_callback
- [x] report_error_callback needs to cast the closure pointer to the new
struct
- [x] the code that [throws a DataClone
error](5d1c64dba9/components/script/dom/bindings/structuredclone.rs (L542))
needs to use the stored error message if it's available

Testing: *Describe how this pull request is tested or why it doesn't
require tests*
Fixes: #36191

---------

Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com>
This commit is contained in:
Jerens Lensun 2025-04-14 02:10:04 +08:00 committed by GitHub
parent 740a94ef20
commit d5284dfad9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 61 additions and 10 deletions

View file

@ -5,6 +5,7 @@
//! This module implements structured cloning, as defined by [HTML](https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).
use std::collections::HashMap;
use std::ffi::CStr;
use std::num::NonZeroU32;
use std::os::raw;
use std::ptr;
@ -312,6 +313,7 @@ unsafe extern "C" fn read_transfer_callback(
let sc_reader = &mut *(closure as *mut StructuredDataReader);
let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx));
let owner = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
for transferrable in TransferrableInterface::iter() {
if tag == StructuredCloneTags::from(transferrable) as u32 {
let transfer_receiver = receiver_for_type(transferrable);
@ -439,9 +441,16 @@ unsafe extern "C" fn can_transfer_callback(
unsafe extern "C" fn report_error_callback(
_cx: *mut JSContext,
_errorid: u32,
_closure: *mut ::std::os::raw::c_void,
_error_message: *const ::std::os::raw::c_char,
closure: *mut raw::c_void,
error_message: *const ::std::os::raw::c_char,
) {
let msg_result = unsafe { CStr::from_ptr(error_message).to_str().map(str::to_string) };
if let Ok(msg) = msg_result {
let dom_error_record = &mut *(closure as *mut DOMErrorRecord);
dom_error_record.message = Some(msg)
}
}
unsafe extern "C" fn sab_cloned_callback(
@ -468,9 +477,18 @@ pub(crate) enum StructuredData<'a> {
Writer(&'a mut StructuredDataWriter),
}
#[derive(Default)]
#[repr(C)]
pub(crate) struct DOMErrorRecord {
pub(crate) message: Option<String>,
}
/// Reader and writer structs for results from, and inputs to, structured-data read/write operations.
/// <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data>
#[repr(C)]
pub(crate) struct StructuredDataReader {
/// A struct of error message.
pub(crate) errors: DOMErrorRecord,
/// A map of deserialized blobs, stored temporarily here to keep them rooted.
pub(crate) blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>,
/// A map of deserialized points, stored temporarily here to keep them rooted.
@ -493,7 +511,10 @@ pub(crate) struct StructuredDataReader {
/// A data holder for transferred and serialized objects.
#[derive(Default)]
#[repr(C)]
pub(crate) struct StructuredDataWriter {
/// Error message.
pub(crate) errors: DOMErrorRecord,
/// Transferred ports.
pub(crate) ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
/// Serialized points.
@ -537,7 +558,7 @@ pub(crate) fn write(
);
if !result {
JS_ClearPendingException(*cx);
return Err(Error::DataClone);
return Err(Error::DataClone(sc_writer.errors.message));
}
let nbytes = GetLengthOfJSStructuredCloneData(scdata);
@ -575,6 +596,7 @@ pub(crate) fn read(
port_impls: data.ports.take(),
blob_impls: data.blobs.take(),
points: data.points.take(),
errors: DOMErrorRecord { message: None },
};
let sc_reader_ptr = &mut sc_reader as *mut _;
unsafe {
@ -605,14 +627,13 @@ pub(crate) fn read(
);
if !result {
JS_ClearPendingException(*cx);
return Err(Error::DataClone);
return Err(Error::DataClone(sc_reader.errors.message));
}
DeleteJSAutoStructuredCloneBuffer(scbuf);
// Any transfer-received port-impls should have been taken out.
assert!(sc_reader.port_impls.is_none());
Ok(sc_reader.message_ports.take().unwrap_or_default())
}
}