From 9b31049f3abd4bb95e898463199861f63fadaf18 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 20 May 2024 13:53:34 -0700 Subject: [PATCH] Minimize safety hazards in `slice_as_uninit[_mut]`. In each function, explicitly use the implicit conversion of `&[T]` to `*const T`/`&mut [T]` to `* mut T` to eliminate one `as *const T`/`as *mut T` respectively. Instead of relying on the remaining cast in each function being valid for all `T`, reduce the scope of the assumption to `u8`, and add a TODO avoid eliminating the use of the assumption. --- src/util.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/util.rs b/src/util.rs index 1c4e70ba..72d3e8fc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -17,11 +17,14 @@ pub fn uninit_slice_fill_zero(slice: &mut [MaybeUninit]) -> &mut [u8] { } #[inline(always)] -pub fn slice_as_uninit(slice: &[T]) -> &[MaybeUninit] { - // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - // There is no risk of writing a `MaybeUninit` into the result since +pub fn slice_as_uninit(slice: &[u8]) -> &[MaybeUninit] { + // TODO: MSRV(1.76): Use `core::ptr::from_ref`. + let ptr: *const [u8] = slice; + // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `u8`. + // There is no risk of writing a `MaybeUninit` into the result since // the result isn't mutable. - unsafe { &*(slice as *const [T] as *const [MaybeUninit]) } + // FIXME: Avoid relying on this assumption and eliminate this cast. + unsafe { &*(ptr as *const [MaybeUninit]) } } /// View an mutable initialized array as potentially-uninitialized. @@ -29,7 +32,10 @@ pub fn slice_as_uninit(slice: &[T]) -> &[MaybeUninit] { /// This is unsafe because it allows assigning uninitialized values into /// `slice`, which would be undefined behavior. #[inline(always)] -pub unsafe fn slice_as_uninit_mut(slice: &mut [T]) -> &mut [MaybeUninit] { - // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - &mut *(slice as *mut [T] as *mut [MaybeUninit]) +pub unsafe fn slice_as_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit] { + // TODO: MSRV(1.76): Use `core::ptr::from_mut`. + let ptr: *mut [u8] = slice; + // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `u8`. + // FIXME: Avoid relying on this assumption and eliminate this cast. + &mut *(ptr as *mut [MaybeUninit]) }