Skip to content

Commit

Permalink
Fix UB in RawStorageMut::swap_unchecked_linear
Browse files Browse the repository at this point in the history
  • Loading branch information
yotamofek committed Nov 13, 2023
1 parent a91e3b0 commit 13d962f
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions src/base/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,21 @@ 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.
#[inline]
unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) {
let a = self.get_address_unchecked_linear_mut(i1);
let b = self.get_address_unchecked_linear_mut(i2);
// we can't just use the pointers returned from `get_address_unchecked_linear_mut` because calling a
// 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 offset1 = self
.get_address_unchecked_linear_mut(i1)
.offset_from(self.ptr());
let offset2 = self
.get_address_unchecked_linear_mut(i2)
.offset_from(self.ptr());
let ptr = self.ptr_mut();
let a = ptr.offset(offset1);
let b = ptr.offset(offset2);

ptr::swap(a, b);
}
Expand Down

0 comments on commit 13d962f

Please sign in to comment.