Skip to content

Commit 14a7af2

Browse files
committed
Mark new_uninitialized_sliced as unsafe
Using a slice of elements that are not properly initialized is UB. Although new_uninitialized_sliced is a private function, mark it as unsafe to make clear that the caller has the responsibility to initialize all elements of the slice without looking at the old contents. For now we need to suppress warnings about the use of unsafe blocks in an unsafe function. This will be changed based on RFC 2585. Marking a function as unsafe and using unsafe code within that function should and will be two different things: rust-lang/rfcs#2585
1 parent 2b51221 commit 14a7af2

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

src/lib.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,12 @@ impl<T> AlignedBox<T> {
139139
Ok((ptr, layout))
140140
}
141141

142-
fn new_uninitialized_sliced(
142+
// # SAFETY
143+
// This function returns a slice of unitialized values. It is the responsibility of
144+
// the caller to initialize all values without looking at the old uninitialized values,
145+
// e.g., using std::ptr::write.
146+
#[allow(unused_unsafe)] // https://github.com/rust-lang/rfcs/pull/2585
147+
unsafe fn new_uninitialized_sliced(
143148
alignment: usize,
144149
nelems: usize,
145150
) -> std::result::Result<AlignedBox<[T]>, std::boxed::Box<dyn std::error::Error>> {
@@ -155,6 +160,8 @@ impl<T> AlignedBox<T> {
155160
// AlignedBox::alocate():
156161
// ptr is non-null, nelems does not exceed the maximum size.
157162
// The referenced memory is not accessed as long as slice exists.
163+
// But: The slice _will_ contain unitialized values. We rely on the caller of
164+
// this function to properly initilize them.
158165
let slice = unsafe { std::slice::from_raw_parts_mut(ptr, nelems) };
159166

160167
// SAFETY: We only create a single Box from the given slice. The slice itself is consumed
@@ -212,7 +219,9 @@ impl<T: Default> AlignedBox<[T]> {
212219
alignment: usize,
213220
nelems: usize,
214221
) -> std::result::Result<AlignedBox<[T]>, std::boxed::Box<dyn std::error::Error>> {
215-
let mut b = AlignedBox::<T>::new_uninitialized_sliced(alignment, nelems)?;
222+
// SAFETY: All elements of the slice are immediately initialized without looking at
223+
// the old (unitialized) value.
224+
let mut b = unsafe { AlignedBox::<T>::new_uninitialized_sliced(alignment, nelems)? };
216225

217226
for i in (*b).iter_mut() {
218227
let d = T::default(); // create new default value
@@ -245,7 +254,9 @@ impl<T: Copy> AlignedBox<[T]> {
245254
nelems: usize,
246255
value: T,
247256
) -> std::result::Result<AlignedBox<[T]>, std::boxed::Box<dyn std::error::Error>> {
248-
let mut b = AlignedBox::<T>::new_uninitialized_sliced(alignment, nelems)?;
257+
// SAFETY: All elements of the slice are immediately initialized without looking at
258+
// the old (unitialized) value.
259+
let mut b = unsafe { AlignedBox::<T>::new_uninitialized_sliced(alignment, nelems)? };
249260

250261
for i in (*b).iter_mut() {
251262
// T is Copy and therefore also !Drop. We can simply copy from value to *i without

0 commit comments

Comments
 (0)