From 53111bf02f2d17a4fa52dc2ee6bebc863fe2f994 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Sun, 11 Oct 2026 22:05:49 +0800 Subject: [PATCH] feat(webidl): write BufferSource rows without changing padding Extracted from wpt-misc-fix. Source-commit: 4fb35a340e3dd773d2f805c5c4e6bed2e8e71b69 --- moli-webidl/src/buffer_source.rs | 17 +++++++++++-- moli-webidl/tests/buffer_source_rows.rs | 33 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 moli-webidl/tests/buffer_source_rows.rs diff --git a/moli-webidl/src/buffer_source.rs b/moli-webidl/src/buffer_source.rs index 9fa4cea8c4..13be7b21ca 100644 --- a/moli-webidl/src/buffer_source.rs +++ b/moli-webidl/src/buffer_source.rs @@ -115,7 +115,20 @@ impl AllowSharedBufferSource<'_> { /// Copy into the native view's byte range, preserving surrounding bytes. pub fn write_bytes(&self, scope: &mut v8::PinScope<'_, '_>, bytes: &[u8]) -> bool { - if bytes.len() > self.byte_length() { + self.write_bytes_at(scope, 0, bytes) + } + + /// Copy a row without touching plane padding or other shared-memory bytes. + pub fn write_bytes_at( + &self, + scope: &mut v8::PinScope<'_, '_>, + start: usize, + bytes: &[u8], + ) -> bool { + if start + .checked_add(bytes.len()) + .is_none_or(|end| end > self.byte_length()) + { return false; } if bytes.is_empty() { @@ -124,7 +137,7 @@ impl AllowSharedBufferSource<'_> { let backing = self .backing_store(scope) .expect("BufferSource has native backing"); - let offset = self.byte_offset(); + let offset = self.byte_offset() + start; if backing.is_shared() { // SAFETY: fixed shared storage is retained and V8 validated the // view range; byte stores are unordered as required for BufferSource. diff --git a/moli-webidl/tests/buffer_source_rows.rs b/moli-webidl/tests/buffer_source_rows.rs new file mode 100644 index 0000000000..4af95d1ee3 --- /dev/null +++ b/moli-webidl/tests/buffer_source_rows.rs @@ -0,0 +1,33 @@ +use moli_webidl::Context; + +#[test] +fn buffer_source_row_writes_preserve_padding_and_reject_out_of_bounds() { + moli_v8_test_util::ensure_v8(); + let mut isolate = v8::Isolate::new(v8::CreateParams::default()); + v8::scope!(let scope, &mut isolate); + let context = v8::Context::new(scope, Default::default()); + let scope = &mut v8::ContextScope::new(scope, context); + for source in [ + "new DataView(new ArrayBuffer(8),2,4)", + "new DataView(new SharedArrayBuffer(8),2,4)", + ] { + let source = v8::String::new(scope, source).unwrap(); + let value = v8::Script::compile(scope, source, None) + .unwrap() + .run(scope) + .unwrap(); + let buffer = moli_webidl::convert::( + scope, + value, + Context::argument("Test", 1), + ) + .unwrap(); + assert!(buffer.write_bytes(scope, &[7, 7, 7, 7])); + assert!(buffer.write_bytes_at(scope, 1, &[1, 2])); + assert_eq!(buffer.to_vec(scope), vec![7, 1, 2, 7]); + assert!(!buffer.write_bytes_at(scope, 3, &[1, 2])); + assert!(!buffer.write_bytes_at(scope, usize::MAX, &[1])); + assert!(buffer.write_bytes_at(scope, 4, &[])); + assert_eq!(buffer.to_vec(scope), vec![7, 1, 2, 7]); + } +}