Skip to content

Commit fd6209d

Browse files
committed
Clarify safety properties of casts between [MaybeUninit<T>] <-> [T].
Reduce the scope of the `unsafe` blocks to the unsafe operations.
1 parent bcbadc1 commit fd6209d

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

src/util.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@ use core::{mem::MaybeUninit, ptr};
66
/// been initialized.
77
#[inline(always)]
88
pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
9-
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
10-
&mut *(slice as *mut [MaybeUninit<T>] as *mut [T])
9+
let ptr: *mut [MaybeUninit<T>] = slice;
10+
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`
11+
// and casting between two slice types of layout-compatible types is sound.
12+
let ptr = ptr as *mut [T];
13+
// SAFETY: ptr was soundly constructed from a valid `&mut` reference so it
14+
// safe to dereference it if the caller has ensured every element of `slice`
15+
// has been ininitialized.
16+
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
17+
unsafe { &mut *ptr }
1118
}
1219

1320
#[inline]
@@ -18,10 +25,16 @@ pub fn uninit_slice_fill_zero(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
1825

1926
#[inline(always)]
2027
pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] {
21-
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
22-
// There is no risk of writing a `MaybeUninit<T>` into the result since
23-
// the result isn't mutable.
24-
unsafe { &*(slice as *const [T] as *const [MaybeUninit<T>]) }
28+
let ptr: *const [T] = slice;
29+
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`
30+
// and casting between two slice types of layout-compatible types is sound.
31+
let ptr = ptr as *const [MaybeUninit<T>];
32+
// SAFETY:
33+
// * ptr was soundly constructed from a valid reference so it safe to
34+
// dereference it.
35+
// * There is no risk of writing a `MaybeUninit<T>` into the result
36+
// since the result isn't mutable.
37+
unsafe { &*ptr }
2538
}
2639

2740
/// View an mutable initialized array as potentially-uninitialized.
@@ -30,6 +43,15 @@ pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] {
3043
/// `slice`, which would be undefined behavior.
3144
#[inline(always)]
3245
pub unsafe fn slice_as_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] {
33-
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
34-
&mut *(slice as *mut [T] as *mut [MaybeUninit<T>])
46+
let ptr: *mut [T] = slice;
47+
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`
48+
// and casting between two slice types of layout-compatible types is sound.
49+
let ptr = ptr as *mut [MaybeUninit<T>];
50+
// SAFETY:
51+
// * ptr was soundly constructed from a valid reference so it safe to
52+
// dereference it.
53+
// * There *IS* a risk of writing a `MaybeUninit<T>` into the result,
54+
// which is why this function is unsafe.
55+
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
56+
unsafe { &mut *ptr }
3557
}

0 commit comments

Comments
 (0)