mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-28 00:00:17 +02:00
Handle unwinding from Box::new (#837)
This commit is contained in:
+36
-23
@@ -1,4 +1,4 @@
|
|||||||
use core::mem::{self, ManuallyDrop};
|
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
||||||
use core::ops::{Deref, RangeBounds};
|
use core::ops::{Deref, RangeBounds};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use core::{cmp, fmt, hash, ptr, slice};
|
use core::{cmp, fmt, hash, ptr, slice};
|
||||||
@@ -946,24 +946,26 @@ impl From<&'static str> for Bytes {
|
|||||||
|
|
||||||
impl From<Vec<u8>> for Bytes {
|
impl From<Vec<u8>> for Bytes {
|
||||||
fn from(vec: Vec<u8>) -> Bytes {
|
fn from(vec: Vec<u8>) -> Bytes {
|
||||||
|
// Avoid an extra allocation if possible.
|
||||||
|
if vec.len() == vec.capacity() {
|
||||||
|
return Bytes::from(vec.into_boxed_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
let shared = Box::new(MaybeUninit::<Shared>::uninit());
|
||||||
let mut vec = ManuallyDrop::new(vec);
|
let mut vec = ManuallyDrop::new(vec);
|
||||||
let ptr = vec.as_mut_ptr();
|
let ptr = vec.as_mut_ptr();
|
||||||
let len = vec.len();
|
let len = vec.len();
|
||||||
let cap = vec.capacity();
|
let cap = vec.capacity();
|
||||||
|
|
||||||
// Avoid an extra allocation if possible.
|
let shared = Shared::init_to_raw(
|
||||||
if len == cap {
|
shared,
|
||||||
let vec = ManuallyDrop::into_inner(vec);
|
Shared {
|
||||||
return Bytes::from(vec.into_boxed_slice());
|
buf: ptr,
|
||||||
}
|
cap,
|
||||||
|
ref_cnt: AtomicUsize::new(1),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let shared = Box::new(Shared {
|
|
||||||
buf: ptr,
|
|
||||||
cap,
|
|
||||||
ref_cnt: AtomicUsize::new(1),
|
|
||||||
});
|
|
||||||
|
|
||||||
let shared = Box::into_raw(shared);
|
|
||||||
// The pointer should be aligned, so this assert should
|
// The pointer should be aligned, so this assert should
|
||||||
// always succeed.
|
// always succeed.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
@@ -1327,6 +1329,15 @@ struct Shared {
|
|||||||
ref_cnt: AtomicUsize,
|
ref_cnt: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Shared {
|
||||||
|
fn init_to_raw(b: Box<MaybeUninit<Self>>, v: Self) -> *mut Self {
|
||||||
|
let shared = Box::into_raw(b).cast::<Self>();
|
||||||
|
// SAFETY: The Box has the right layout.
|
||||||
|
unsafe { shared.write(v) };
|
||||||
|
shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for Shared {
|
impl Drop for Shared {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { dealloc(self.buf, Layout::from_size_align(self.cap, 1).unwrap()) }
|
unsafe { dealloc(self.buf, Layout::from_size_align(self.cap, 1).unwrap()) }
|
||||||
@@ -1472,16 +1483,18 @@ unsafe fn shallow_clone_vec(
|
|||||||
// updated and since the buffer hasn't been promoted to an
|
// updated and since the buffer hasn't been promoted to an
|
||||||
// `Arc`, those three fields still are the components of the
|
// `Arc`, those three fields still are the components of the
|
||||||
// vector.
|
// vector.
|
||||||
let shared = Box::new(Shared {
|
let shared = Box::new(MaybeUninit::<Shared>::uninit());
|
||||||
buf,
|
let shared = Shared::init_to_raw(
|
||||||
cap: offset.offset_from(buf) as usize + len,
|
shared,
|
||||||
// Initialize refcount to 2. One for this reference, and one
|
Shared {
|
||||||
// for the new clone that will be returned from
|
buf,
|
||||||
// `shallow_clone`.
|
cap: offset.offset_from(buf) as usize + len,
|
||||||
ref_cnt: AtomicUsize::new(2),
|
// Initialize refcount to 2. One for this reference, and one
|
||||||
});
|
// for the new clone that will be returned from
|
||||||
|
// `shallow_clone`.
|
||||||
let shared = Box::into_raw(shared);
|
ref_cnt: AtomicUsize::new(2),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// The pointer should be aligned, so this assert should
|
// The pointer should be aligned, so this assert should
|
||||||
// always succeed.
|
// always succeed.
|
||||||
|
|||||||
+21
-7
@@ -79,6 +79,15 @@ struct Shared {
|
|||||||
ref_count: AtomicUsize,
|
ref_count: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Shared {
|
||||||
|
fn init_to_raw(b: Box<MaybeUninit<Self>>, v: Self) -> *mut Self {
|
||||||
|
let shared = Box::into_raw(b).cast::<Self>();
|
||||||
|
// SAFETY: The Box has the right layout.
|
||||||
|
unsafe { shared.write(v) };
|
||||||
|
shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Assert that the alignment of `Shared` is divisible by 2.
|
// Assert that the alignment of `Shared` is divisible by 2.
|
||||||
// This is a necessary invariant since we depend on allocating `Shared` a
|
// This is a necessary invariant since we depend on allocating `Shared` a
|
||||||
// shared object to implicitly carry the `KIND_ARC` flag in its pointer.
|
// shared object to implicitly carry the `KIND_ARC` flag in its pointer.
|
||||||
@@ -1112,13 +1121,18 @@ impl BytesMut {
|
|||||||
// updated and since the buffer hasn't been promoted to an
|
// updated and since the buffer hasn't been promoted to an
|
||||||
// `Arc`, those three fields still are the components of the
|
// `Arc`, those three fields still are the components of the
|
||||||
// vector.
|
// vector.
|
||||||
let shared = Box::new(Shared {
|
//
|
||||||
vec: rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off),
|
// Explicitly allocate before invoking rebuild_vec() so that
|
||||||
original_capacity_repr,
|
// the vector is not dropped if Box::new() panics.
|
||||||
ref_count: AtomicUsize::new(ref_cnt),
|
let shared = Box::new(MaybeUninit::<Shared>::uninit());
|
||||||
});
|
let shared = Shared::init_to_raw(
|
||||||
|
shared,
|
||||||
let shared = Box::into_raw(shared);
|
Shared {
|
||||||
|
vec: rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off),
|
||||||
|
original_capacity_repr,
|
||||||
|
ref_count: AtomicUsize::new(ref_cnt),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// The pointer should be aligned, so this assert should
|
// The pointer should be aligned, so this assert should
|
||||||
// always succeed.
|
// always succeed.
|
||||||
|
|||||||
Reference in New Issue
Block a user