From adc3a8103b90d8c4442a7f3d3d51ce8a4580d9fd Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 13 Nov 2023 10:35:46 +0000 Subject: [PATCH] Fix UB in `RawStorageMut::swap_unchecked_linear` --- src/base/storage.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/base/storage.rs b/src/base/storage.rs index d5f1de61..fc40bb41 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -208,8 +208,19 @@ pub unsafe trait RawStorageMut: RawStorage { /// 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 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); }