Skip to content

Commit 394a884

Browse files
committed
Fix {to,from}_array UB when repr(simd) produces padding
1 parent ad8afa8 commit 394a884

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

crates/core_simd/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#![feature(
33
const_ptr_read,
44
const_refs_to_cell,
5+
const_maybe_uninit_as_mut_ptr,
6+
const_mut_refs,
57
convert_float_to_int,
68
decl_macro,
79
intra_doc_pointers,

crates/core_simd/src/vector.rs

+42-14
Original file line numberDiff line numberDiff line change
@@ -176,34 +176,62 @@ where
176176
unsafe { &mut *(self as *mut Self as *mut [T; N]) }
177177
}
178178

179+
/// Load a vector from an array of `T`.
180+
///
181+
/// This function is necessary since `repr(simd)` has padding for non-power-of-2 vectors (at the time of writing).
182+
/// With padding, `read_unaligned` will read past the end of an array of N elements.
183+
///
184+
/// # Safety
185+
/// Reading `ptr` must be safe, as if by `<*const [T; N]>::read_unaligned`.
186+
const unsafe fn load(ptr: *const [T; N]) -> Self {
187+
let mut tmp = core::mem::MaybeUninit::uninit();
188+
// SAFETY: `Simd<T, N>` always contains `N` elements of type `T`. It may have padding
189+
// which does not need to be initialized. The safety of reading `ptr` is ensured by the
190+
// caller.
191+
unsafe {
192+
core::ptr::copy_nonoverlapping(ptr, tmp.as_mut_ptr() as *mut _, 1);
193+
tmp.assume_init()
194+
}
195+
}
196+
197+
/// Store a vector to an array of `T`.
198+
///
199+
/// See `load` as to why this function is necessary.
200+
///
201+
/// # Safety
202+
/// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write_unaligned`.
203+
const unsafe fn store(self, ptr: *mut [T; N]) {
204+
// SAFETY: `Simd<T, N>` always contains `N` elements of type `T`. The safety of writing
205+
// `ptr` is ensured by the caller.
206+
unsafe { core::ptr::copy_nonoverlapping(self.as_array(), ptr, 1) }
207+
}
208+
179209
/// Converts an array to a SIMD vector.
180210
pub const fn from_array(array: [T; N]) -> Self {
181-
// SAFETY: Transmuting between `Simd<T, N>` and `[T; N]`
182-
// is always valid. We need to use `read_unaligned` here, since
183-
// the array may have a lower alignment than the vector.
211+
// SAFETY: `&array` is safe to read.
184212
//
185-
// FIXME: We currently use a pointer read instead of `transmute_copy` because
186-
// it results in better codegen with optimizations disabled, but we should
187-
// probably just use `transmute` once that works on const generic types.
213+
// FIXME: We currently use a pointer load instead of `transmute_copy` because `repr(simd)`
214+
// results in padding for non-power-of-2 vectors (so vectors are larger than arrays).
188215
//
189216
// NOTE: This deliberately doesn't just use `Self(array)`, see the comment
190217
// on the struct definition for details.
191-
unsafe { (&array as *const [T; N] as *const Self).read_unaligned() }
218+
unsafe { Self::load(&array) }
192219
}
193220

194221
/// Converts a SIMD vector to an array.
195222
pub const fn to_array(self) -> [T; N] {
196-
// SAFETY: Transmuting between `Simd<T, N>` and `[T; N]`
197-
// is always valid. No need to use `read_unaligned` here, since
198-
// the vector never has a lower alignment than the array.
223+
let mut tmp = core::mem::MaybeUninit::uninit();
224+
// SAFETY: writing to `tmp` is safe and initializes it.
199225
//
200-
// FIXME: We currently use a pointer read instead of `transmute_copy` because
201-
// it results in better codegen with optimizations disabled, but we should
202-
// probably just use `transmute` once that works on const generic types.
226+
// FIXME: We currently use a pointer store instead of `transmute_copy` because `repr(simd)`
227+
// results in padding for non-power-of-2 vectors (so vectors are larger than arrays).
203228
//
204229
// NOTE: This deliberately doesn't just use `self.0`, see the comment
205230
// on the struct definition for details.
206-
unsafe { (&self as *const Self as *const [T; N]).read() }
231+
unsafe {
232+
self.store(tmp.as_mut_ptr());
233+
tmp.assume_init()
234+
}
207235
}
208236

209237
/// Converts a slice to a SIMD vector containing `slice[..N]`.

0 commit comments

Comments
 (0)