Fix UB in `RawStorageMut::swap_unchecked_linear`

This commit is contained in:
Yotam Ofek 2023-11-13 10:35:46 +00:00
parent 0b89950fca
commit adc3a8103b
1 changed files with 13 additions and 2 deletions

View File

@ -208,8 +208,19 @@ pub unsafe trait RawStorageMut<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
/// If the indices are out of bounds, the method will cause undefined behavior. /// If the indices are out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) { unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) {
let a = self.get_address_unchecked_linear_mut(i1); // we can't just use the pointers returned from `get_address_unchecked_linear_mut` because calling a
let b = self.get_address_unchecked_linear_mut(i2); // method taking self mutably invalidates any existing (mutable) pointers. since `get_address_unchecked_linear_mut` can
// also be overriden by a custom implementation, we can't just use `wrapping_add` assuming that's what the method does.
// instead, we use `offset_from` to compute the re-calculate the pointers from the base pointer.
// this is safe as long as this trait is implemented safely
// (and it's the caller's responsibility to ensure the indices are in-bounds).
let base = self.ptr_mut();
let offset1 = self.get_address_unchecked_linear_mut(i1).offset_from(base);
let offset2 = self.get_address_unchecked_linear_mut(i2).offset_from(base);
let base = self.ptr_mut();
let a = base.offset(offset1);
let b = base.offset(offset2);
ptr::swap(a, b); ptr::swap(a, b);
} }