Fix UB when dropping BoxBytes owning a zero-sized layout (#258)

This commit is contained in:
zachs18 2024-07-30 22:23:38 +00:00 committed by GitHub
parent 005ee3254f
commit 1c75146bb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 4 deletions

View File

@ -742,8 +742,9 @@ impl<I: ?Sized, T: ?Sized + TransparentWrapper<I>> TransparentWrapperAlloc<I>
/// As `Box<[u8]>`, but remembers the original alignment. /// As `Box<[u8]>`, but remembers the original alignment.
pub struct BoxBytes { pub struct BoxBytes {
// SAFETY: `ptr` is owned, was allocated with `layout`, and points to // SAFETY: `ptr` is owned, points to `layout.size()` initialized bytes, and
// `layout.size()` initialized bytes. // was allocated with `layout` (unless `layout.size() == 0` in which case it
// is dangling).
ptr: NonNull<u8>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
} }
@ -770,9 +771,12 @@ impl DerefMut for BoxBytes {
impl Drop for BoxBytes { impl Drop for BoxBytes {
fn drop(&mut self) { fn drop(&mut self) {
// SAFETY: See type invariant. if self.layout.size() != 0 {
// SAFETY: See type invariant: if `self.layout.size() != 0`, then
// `self.ptr` is owned and was allocated with `self.layout`.
unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) }; unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) };
} }
}
} }
impl<T: ?Sized + sealed::BoxBytesOf> From<Box<T>> for BoxBytes { impl<T: ?Sized + sealed::BoxBytesOf> From<Box<T>> for BoxBytes {

View File

@ -328,3 +328,17 @@ fn test_arc_slices() {
let empty: Arc<[i8]> = cast_slice_arc::<(), i8>(Arc::new([(); 42])); let empty: Arc<[i8]> = cast_slice_arc::<(), i8>(Arc::new([(); 42]));
assert!(empty.is_empty()); assert!(empty.is_empty());
} }
#[cfg(feature = "extern_crate_alloc")]
#[test]
fn box_bytes_zst() {
let x: BoxBytes = box_bytes_of(Box::new([0u8; 0]));
let _: Box<[u8]> = from_box_bytes(x);
let x: BoxBytes = box_bytes_of(Box::new([0u8; 0]));
let res: Result<Box<[()]>, _> = try_from_box_bytes(x);
assert_eq!(res.unwrap_err().0, PodCastError::SizeMismatch);
let x: BoxBytes = box_bytes_of(Box::new([(); 0]));
let _: Box<[u8]> = from_box_bytes(x);
}