mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-21 15:04:33 -05:00
fix: arraybuffer init from vec was broken if vec reallocated to box (#1341)
This commit is contained in:
parent
088c998929
commit
efca1408f6
3 changed files with 70 additions and 31 deletions
|
@ -3,7 +3,6 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr;
|
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
@ -248,7 +247,7 @@ pub type BackingStoreDeleterCallback = unsafe extern "C" fn(
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
pub trait Rawable<T: ?Sized> {
|
pub trait Rawable<T: ?Sized> {
|
||||||
fn into_raw(self) -> *const ();
|
fn into_raw(self) -> (*const (), *const u8);
|
||||||
unsafe fn drop_raw(ptr: *const (), size: usize);
|
unsafe fn drop_raw(ptr: *const (), size: usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,37 +257,39 @@ impl sealed::Rawable<[u8]> for Vec<u8> {
|
||||||
<Box<[u8]> as sealed::Rawable<[u8]>>::drop_raw(ptr, size);
|
<Box<[u8]> as sealed::Rawable<[u8]>>::drop_raw(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_raw(self) -> *const () {
|
fn into_raw(self) -> (*const (), *const u8) {
|
||||||
self.into_boxed_slice().into_raw()
|
self.into_boxed_slice().into_raw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! rawable {
|
impl<T: Sized> sealed::Rawable<T> for Box<T>
|
||||||
($container:ident) => {
|
where
|
||||||
impl<T: Sized> sealed::Rawable<T> for $container<T> {
|
T: AsMut<[u8]>,
|
||||||
fn into_raw(self) -> *const () {
|
{
|
||||||
Self::into_raw(self) as _
|
fn into_raw(mut self) -> (*const (), *const u8) {
|
||||||
}
|
let data = self.as_mut().as_mut().as_mut_ptr();
|
||||||
|
let ptr = Self::into_raw(self);
|
||||||
|
(ptr as _, data)
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn drop_raw(ptr: *const (), _len: usize) {
|
unsafe fn drop_raw(ptr: *const (), _len: usize) {
|
||||||
_ = Self::from_raw(ptr as _);
|
_ = Self::from_raw(ptr as _);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl sealed::Rawable<[u8]> for $container<[u8]> {
|
|
||||||
fn into_raw(self) -> *const () {
|
|
||||||
Self::into_raw(self) as _
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn drop_raw(ptr: *const (), len: usize) {
|
|
||||||
_ = Self::from_raw(ptr::slice_from_raw_parts_mut(ptr as _, len));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement Rawable for single-ownership container types
|
impl sealed::Rawable<[u8]> for Box<[u8]> {
|
||||||
rawable!(Box);
|
fn into_raw(mut self) -> (*const (), *const u8) {
|
||||||
|
// Thin the fat pointer
|
||||||
|
let ptr = self.as_mut_ptr();
|
||||||
|
std::mem::forget(self);
|
||||||
|
(ptr as _, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop_raw(ptr: *const (), len: usize) {
|
||||||
|
// Fatten the thin pointer
|
||||||
|
_ = Self::from_raw(std::ptr::slice_from_raw_parts_mut(ptr as _, len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A wrapper around the backing store (i.e. the raw memory) of an array buffer.
|
/// A wrapper around the backing store (i.e. the raw memory) of an array buffer.
|
||||||
/// See a document linked in http://crbug.com/v8/9908 for more information.
|
/// See a document linked in http://crbug.com/v8/9908 for more information.
|
||||||
|
@ -567,8 +568,13 @@ impl ArrayBuffer {
|
||||||
T: sealed::Rawable<U>,
|
T: sealed::Rawable<U>,
|
||||||
{
|
{
|
||||||
let len = bytes.as_mut().as_mut().len();
|
let len = bytes.as_mut().as_mut().len();
|
||||||
let slice = bytes.as_mut().as_mut().as_mut_ptr();
|
if len == 0 {
|
||||||
let ptr = T::into_raw(bytes);
|
return unsafe {
|
||||||
|
UniqueRef::from_raw(v8__BackingStore__EmptyBackingStore(false))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ptr, slice) = T::into_raw(bytes);
|
||||||
|
|
||||||
extern "C" fn drop_rawable<T: sealed::Rawable<U>, U: ?Sized>(
|
extern "C" fn drop_rawable<T: sealed::Rawable<U>, U: ?Sized>(
|
||||||
_ptr: *mut c_void,
|
_ptr: *mut c_void,
|
||||||
|
|
|
@ -176,8 +176,13 @@ impl SharedArrayBuffer {
|
||||||
T: crate::array_buffer::sealed::Rawable<U>,
|
T: crate::array_buffer::sealed::Rawable<U>,
|
||||||
{
|
{
|
||||||
let len = bytes.as_mut().as_mut().len();
|
let len = bytes.as_mut().as_mut().len();
|
||||||
let slice = bytes.as_mut().as_mut().as_mut_ptr();
|
if len == 0 {
|
||||||
let ptr = T::into_raw(bytes);
|
return unsafe {
|
||||||
|
UniqueRef::from_raw(v8__BackingStore__EmptyBackingStore(false))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ptr, slice) = T::into_raw(bytes);
|
||||||
|
|
||||||
extern "C" fn drop_rawable<
|
extern "C" fn drop_rawable<
|
||||||
T: crate::array_buffer::sealed::Rawable<U>,
|
T: crate::array_buffer::sealed::Rawable<U>,
|
||||||
|
|
|
@ -834,13 +834,41 @@ fn array_buffer() {
|
||||||
assert_eq!(0, ab.byte_length());
|
assert_eq!(0, ab.byte_length());
|
||||||
assert!(!ab.get_backing_store().is_shared());
|
assert!(!ab.get_backing_store().is_shared());
|
||||||
|
|
||||||
|
// Empty but from vec
|
||||||
|
let ab = v8::ArrayBuffer::with_backing_store(
|
||||||
|
scope,
|
||||||
|
&v8::ArrayBuffer::new_backing_store_from_bytes(vec![]).make_shared(),
|
||||||
|
);
|
||||||
|
assert_eq!(0, ab.byte_length());
|
||||||
|
assert!(!ab.get_backing_store().is_shared());
|
||||||
|
|
||||||
|
// Empty but from vec with a huge capacity
|
||||||
|
let mut v = Vec::with_capacity(10_000_000);
|
||||||
|
v.extend_from_slice(&[1, 2, 3, 4]);
|
||||||
|
let ab = v8::ArrayBuffer::with_backing_store(
|
||||||
|
scope,
|
||||||
|
&v8::ArrayBuffer::new_backing_store_from_bytes(v).make_shared(),
|
||||||
|
);
|
||||||
|
// Allocate a completely unused buffer overtop of the old allocation
|
||||||
|
let mut v2: Vec<u8> = Vec::with_capacity(10_000_000);
|
||||||
|
v2.extend_from_slice(&[10, 20, 30, 40]);
|
||||||
|
// Make sure the the arraybuffer didn't get stomped
|
||||||
|
assert_eq!(4, ab.byte_length());
|
||||||
|
assert_eq!(1, ab.get_backing_store()[0].get());
|
||||||
|
assert_eq!(2, ab.get_backing_store()[1].get());
|
||||||
|
assert_eq!(3, ab.get_backing_store()[2].get());
|
||||||
|
assert_eq!(4, ab.get_backing_store()[3].get());
|
||||||
|
assert!(!ab.get_backing_store().is_shared());
|
||||||
|
drop(v2);
|
||||||
|
|
||||||
// From a bytes::BytesMut
|
// From a bytes::BytesMut
|
||||||
let mut data = bytes::BytesMut::new();
|
let mut data = bytes::BytesMut::new();
|
||||||
data.extend_from_slice(&[0; 16]);
|
data.extend_from_slice(&[100; 16]);
|
||||||
data[0] = 1;
|
data[0] = 1;
|
||||||
let unique_bs =
|
let unique_bs =
|
||||||
v8::ArrayBuffer::new_backing_store_from_bytes(Box::new(data));
|
v8::ArrayBuffer::new_backing_store_from_bytes(Box::new(data));
|
||||||
assert_eq!(unique_bs.get(0).unwrap().get(), 1);
|
assert_eq!(unique_bs.get(0).unwrap().get(), 1);
|
||||||
|
assert_eq!(unique_bs.get(15).unwrap().get(), 100);
|
||||||
|
|
||||||
let ab =
|
let ab =
|
||||||
v8::ArrayBuffer::with_backing_store(scope, &unique_bs.make_shared());
|
v8::ArrayBuffer::with_backing_store(scope, &unique_bs.make_shared());
|
||||||
|
|
Loading…
Reference in a new issue