From 7919e4208b0a7937a1407523c7f4181aca8c85b7 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 21 Feb 2022 17:30:42 -0500 Subject: [PATCH 1/3] Fix slice::ChunksMut aliasing --- library/core/src/slice/iter.rs | 171 +++++++++++++++++++-------------- library/core/tests/slice.rs | 44 +++++++++ 2 files changed, 143 insertions(+), 72 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 35d00b9dda6..d085b516667 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1629,14 +1629,15 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksMut<'a, T: 'a> { - v: &'a mut [T], + v: *mut [T], chunk_size: usize, + _marker: PhantomData<&'a mut T>, } impl<'a, T: 'a> ChunksMut<'a, T> { #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { - Self { v: slice, chunk_size: size } + Self { v: slice, chunk_size: size, _marker: PhantomData } } } @@ -1650,10 +1651,11 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); + // SAFETY: sz cannot exceed the slice length based on the calculation above + let (head, tail) = unsafe { self.v.split_at_mut(sz) }; self.v = tail; - Some(head) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *head }) } } @@ -1685,11 +1687,13 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { Some(sum) => cmp::min(self.v.len(), sum), None => self.v.len(), }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(end); - let (_, nth) = head.split_at_mut(start); + // SAFETY: end is inbounds because we compared above against self.v.len() + let (head, tail) = unsafe { self.v.split_at_mut(end) }; + // SAFETY: start is inbounds because + let (_, nth) = unsafe { head.split_at_mut(start) }; self.v = tail; - Some(nth) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth }) } } @@ -1699,7 +1703,8 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&mut self.v[start..]) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *self.v.get_unchecked_mut(start..) }) } } @@ -1727,12 +1732,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { } else { let remainder = self.v.len() % self.chunk_size; let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); + let len = self.v.len(); // SAFETY: Similar to `Chunks::next_back` - let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) }; + let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; self.v = head; - Some(tail) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *tail }) } } @@ -1748,10 +1753,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); + // SAFETY: end is inbounds because we compared above against self.v.len() + let (temp, _tail) = unsafe { self.v.split_at_mut(end) }; + let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; - Some(nth_back) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth_back }) } } } @@ -1957,9 +1964,10 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { #[stable(feature = "chunks_exact", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], + v: *mut [T], + rem: &'a mut [T], // The iterator never yields from here, so this can be unique chunk_size: usize, + _marker: PhantomData<&'a mut T>, } impl<'a, T> ChunksExactMut<'a, T> { @@ -1969,7 +1977,7 @@ impl<'a, T> ChunksExactMut<'a, T> { let fst_len = slice.len() - rem; // SAFETY: 0 <= fst_len <= slice.len() by construction above let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) }; - Self { v: fst, rem: snd, chunk_size } + Self { v: fst, rem: snd, chunk_size, _marker: PhantomData } } /// Returns the remainder of the original slice that is not going to be @@ -1991,10 +1999,11 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); + // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len() + let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; self.v = tail; - Some(head) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *head }) } } @@ -2016,8 +2025,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { self.v = &mut []; None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (_, snd) = tmp.split_at_mut(start); + let (_, snd) = unsafe { self.v.split_at_mut(start) }; self.v = snd; self.next() } @@ -2042,11 +2050,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + // SAFETY: This subtraction is inbounds because of the check above + let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) }; self.v = head; - Some(tail) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *tail }) } } @@ -2059,10 +2067,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); + let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) }; + let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; - Some(nth_back) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth_back }) } } } @@ -2646,14 +2655,15 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksMut<'a, T: 'a> { - v: &'a mut [T], + v: *mut [T], chunk_size: usize, + _marker: PhantomData<&'a mut T>, } impl<'a, T: 'a> RChunksMut<'a, T> { #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { - Self { v: slice, chunk_size: size } + Self { v: slice, chunk_size: size, _marker: PhantomData } } } @@ -2667,16 +2677,16 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); + let len = self.v.len(); // SAFETY: split_at_mut_unchecked just requires the argument be less // than the length. This could only happen if the expression - // `tmp_len - sz` overflows. This could only happen if `sz > - // tmp_len`, which is impossible as we initialize it as the `min` of - // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`. - let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) }; + // `len - sz` overflows. This could only happen if `sz > + // len`, which is impossible as we initialize it as the `min` of + // `self.v.len()` (e.g. `len`) and `self.chunk_size`. + let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; self.v = head; - Some(tail) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *tail }) } } @@ -2710,11 +2720,11 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { Some(sum) => sum, None => 0, }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(start); - let (nth, _) = tail.split_at_mut(end - start); + let (head, tail) = unsafe { self.v.split_at_mut(start) }; + let (nth, _) = unsafe { tail.split_at_mut(end - start) }; self.v = head; - Some(nth) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth }) } } @@ -2725,7 +2735,8 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } else { let rem = self.v.len() % self.chunk_size; let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&mut self.v[0..end]) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) }) } } @@ -2750,11 +2761,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { } else { let remainder = self.v.len() % self.chunk_size; let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); // SAFETY: Similar to `Chunks::next_back` - let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) }; + let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) }; self.v = tail; - Some(head) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *head }) } } @@ -2769,10 +2780,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); + let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; + let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; - Some(nth_back) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth_back }) } } } @@ -2898,8 +2910,7 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; - // SAFETY: - // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`. + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } } @@ -2982,7 +2993,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksExactMut<'a, T: 'a> { - v: &'a mut [T], + v: *mut [T], rem: &'a mut [T], chunk_size: usize, } @@ -3015,11 +3026,11 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + let len = self.v.len(); + let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) }; self.v = head; - Some(tail) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *tail }) } } @@ -3041,9 +3052,8 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { self.v = &mut []; None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (fst, _) = tmp.split_at_mut(tmp_len - end); + let len = self.v.len(); + let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; self.v = fst; self.next() } @@ -3069,10 +3079,10 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); + let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; self.v = tail; - Some(head) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *head }) } } @@ -3088,10 +3098,11 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { let offset = (len - n) * self.chunk_size; let start = self.v.len() - offset; let end = start + self.chunk_size; - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); + let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; + let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; - Some(nth_back) + // SAFETY: Nothing points to or will point to the contents of this slice + Some(unsafe { &mut *nth_back }) } } } @@ -3174,7 +3185,11 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next() { - if (self.predicate)(l, r) { len += 1 } else { break } + if (self.predicate)(l, r) { + len += 1 + } else { + break; + } } let (head, tail) = self.slice.split_at(len); self.slice = tail; @@ -3206,7 +3221,11 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next_back() { - if (self.predicate)(l, r) { len += 1 } else { break } + if (self.predicate)(l, r) { + len += 1 + } else { + break; + } } let (head, tail) = self.slice.split_at(self.slice.len() - len); self.slice = head; @@ -3261,7 +3280,11 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next() { - if (self.predicate)(l, r) { len += 1 } else { break } + if (self.predicate)(l, r) { + len += 1 + } else { + break; + } } let slice = mem::take(&mut self.slice); let (head, tail) = slice.split_at_mut(len); @@ -3294,7 +3317,11 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next_back() { - if (self.predicate)(l, r) { len += 1 } else { break } + if (self.predicate)(l, r) { + len += 1 + } else { + break; + } } let slice = mem::take(&mut self.slice); let (head, tail) = slice.split_at_mut(slice.len() - len); diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 5751a91721d..6d1516958f3 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -409,6 +409,50 @@ fn test_chunks_mut_zip() { assert_eq!(v1, [13, 14, 19, 20, 14]); } +#[test] +fn test_chunks_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.chunks_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); +} + +#[test] +fn test_chunks_exact_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); +} + +#[test] +fn test_rchunks_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.rchunks_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); +} + +#[test] +fn test_rchunks_exact_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); +} + #[test] fn test_chunks_exact_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; From e2e3a887710b281ccc0e4e841c6fd4d5f95d85fc Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 26 Jul 2022 18:37:00 -0400 Subject: [PATCH 2/3] Explain how *mut [T] helps, and how we rely on the check in split_at_mut --- library/core/src/slice/iter.rs | 75 +++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index d085b516667..fdbc9fd0b5b 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1629,6 +1629,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksMut<'a, T: 'a> { + // This slice pointer must point at a valid region of T with at least length v.len(). Normally, + // those requirements would mean that we could instead use a &mut [T] here, but we cannot + // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing + // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw + // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. v: *mut [T], chunk_size: usize, _marker: PhantomData<&'a mut T>, @@ -1651,10 +1656,10 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - // SAFETY: sz cannot exceed the slice length based on the calculation above + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, tail) = unsafe { self.v.split_at_mut(sz) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *head }) } } @@ -1687,12 +1692,12 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { Some(sum) => cmp::min(self.v.len(), sum), None => self.v.len(), }; - // SAFETY: end is inbounds because we compared above against self.v.len() + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: start is inbounds because + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (_, nth) = unsafe { head.split_at_mut(start) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth }) } } @@ -1703,7 +1708,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *self.v.get_unchecked_mut(start..) }) } } @@ -1736,7 +1741,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { // SAFETY: Similar to `Chunks::next_back` let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *tail }) } } @@ -1753,11 +1758,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; - // SAFETY: end is inbounds because we compared above against self.v.len() + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (temp, _tail) = unsafe { self.v.split_at_mut(end) }; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) } } @@ -1964,6 +1970,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { #[stable(feature = "chunks_exact", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksExactMut<'a, T: 'a> { + // This slice pointer must point at a valid region of T with at least length v.len(). Normally, + // those requirements would mean that we could instead use a &mut [T] here, but we cannot + // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing + // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw + // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. v: *mut [T], rem: &'a mut [T], // The iterator never yields from here, so this can be unique chunk_size: usize, @@ -2002,7 +2013,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len() let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *head }) } } @@ -2025,6 +2036,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { self.v = &mut []; None } else { + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (_, snd) = unsafe { self.v.split_at_mut(start) }; self.v = snd; self.next() @@ -2053,7 +2065,7 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { // SAFETY: This subtraction is inbounds because of the check above let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *tail }) } } @@ -2067,10 +2079,12 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) }; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) } } @@ -2655,6 +2669,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksMut<'a, T: 'a> { + // This slice pointer must point at a valid region of T with at least length v.len(). Normally, + // those requirements would mean that we could instead use a &mut [T] here, but we cannot + // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing + // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw + // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. v: *mut [T], chunk_size: usize, _marker: PhantomData<&'a mut T>, @@ -2685,7 +2704,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { // `self.v.len()` (e.g. `len`) and `self.chunk_size`. let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *tail }) } } @@ -2720,10 +2739,14 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { Some(sum) => sum, None => 0, }; + // SAFETY: This type ensures that self.v is a valid pointer with a correct len. + // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. let (head, tail) = unsafe { self.v.split_at_mut(start) }; + // SAFETY: This type ensures that self.v is a valid pointer with a correct len. + // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. let (nth, _) = unsafe { tail.split_at_mut(end - start) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth }) } } @@ -2735,7 +2758,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } else { let rem = self.v.len() % self.chunk_size; let end = if rem == 0 { self.chunk_size } else { rem }; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) }) } } @@ -2764,7 +2787,7 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { // SAFETY: Similar to `Chunks::next_back` let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *head }) } } @@ -2780,10 +2803,12 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) } } @@ -2993,6 +3018,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksExactMut<'a, T: 'a> { + // This slice pointer must point at a valid region of T with at least length v.len(). Normally, + // those requirements would mean that we could instead use a &mut [T] here, but we cannot + // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing + // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw + // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. v: *mut [T], rem: &'a mut [T], chunk_size: usize, @@ -3027,9 +3057,10 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { None } else { let len = self.v.len(); + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) }; self.v = head; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *tail }) } } @@ -3053,6 +3084,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { None } else { let len = self.v.len(); + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; self.v = fst; self.next() @@ -3079,9 +3111,10 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *head }) } } @@ -3098,10 +3131,12 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { let offset = (len - n) * self.chunk_size; let start = self.v.len() - offset; let end = start + self.chunk_size; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; + // SAFETY: This type ensures that any split_at_mut on self.v is valid. let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; - // SAFETY: Nothing points to or will point to the contents of this slice + // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) } } From 746afe8952a026c24fd229474f40658cbc9e12c7 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 26 Jul 2022 20:47:53 -0400 Subject: [PATCH 3/3] Clarify safety comments --- library/core/src/slice/iter.rs | 106 +++++++++++++++------------------ 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index fdbc9fd0b5b..dea72813365 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1629,11 +1629,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksMut<'a, T: 'a> { - // This slice pointer must point at a valid region of T with at least length v.len(). Normally, - // those requirements would mean that we could instead use a &mut [T] here, but we cannot - // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing - // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw - // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. + /// # Safety + /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, + /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot + /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing + /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw + /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. v: *mut [T], chunk_size: usize, _marker: PhantomData<&'a mut T>, @@ -1656,7 +1657,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, tail) = unsafe { self.v.split_at_mut(sz) }; self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -1692,9 +1693,9 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { Some(sum) => cmp::min(self.v.len(), sum), None => self.v.len(), }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (_, nth) = unsafe { head.split_at_mut(start) }; self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -1715,7 +1716,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. + // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`. // // Also note that the caller also guarantees that we're never called // with the same index again, and that no other methods that will @@ -1758,9 +1759,9 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (temp, _tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -1970,11 +1971,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { #[stable(feature = "chunks_exact", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ChunksExactMut<'a, T: 'a> { - // This slice pointer must point at a valid region of T with at least length v.len(). Normally, - // those requirements would mean that we could instead use a &mut [T] here, but we cannot - // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing - // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw - // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. + /// # Safety + /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, + /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot + /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing + /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw + /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. v: *mut [T], rem: &'a mut [T], // The iterator never yields from here, so this can be unique chunk_size: usize, @@ -2036,7 +2038,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { self.v = &mut []; None } else { - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (_, snd) = unsafe { self.v.split_at_mut(start) }; self.v = snd; self.next() @@ -2050,7 +2052,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. + // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } @@ -2079,9 +2081,9 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, nth_back) = unsafe { temp.split_at_mut(start) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -2669,11 +2671,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksMut<'a, T: 'a> { - // This slice pointer must point at a valid region of T with at least length v.len(). Normally, - // those requirements would mean that we could instead use a &mut [T] here, but we cannot - // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing - // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw - // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. + /// # Safety + /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, + /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot + /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing + /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw + /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. v: *mut [T], chunk_size: usize, _marker: PhantomData<&'a mut T>, @@ -2770,7 +2773,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { Some(start) => start, }; // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and - // `ChunksMut::__iterator_get_unchecked` + // `ChunksMut::__iterator_get_unchecked`, `self.v`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } } } @@ -2803,9 +2806,9 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -3018,11 +3021,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { #[stable(feature = "rchunks", since = "1.31.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct RChunksExactMut<'a, T: 'a> { - // This slice pointer must point at a valid region of T with at least length v.len(). Normally, - // those requirements would mean that we could instead use a &mut [T] here, but we cannot - // because __iterator_get_unchecked needs to return &mut [T], which guarantees certain aliasing - // properties that we cannot uphold if we hold on to the full original &mut [T]. Wrapping a raw - // slice instead lets us hand out non-overlapping &mut [T] subslices of the slice we wrap. + /// # Safety + /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally, + /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot + /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing + /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw + /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap. v: *mut [T], rem: &'a mut [T], chunk_size: usize, @@ -3057,7 +3061,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { None } else { let len = self.v.len(); - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -3084,7 +3088,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { None } else { let len = self.v.len(); - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; self.v = fst; self.next() @@ -3099,7 +3103,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`. + // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked` and `self.v`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } @@ -3111,7 +3115,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { if self.v.len() < self.chunk_size { None } else { - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -3131,9 +3135,9 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { let offset = (len - n) * self.chunk_size; let start = self.v.len() - offset; let end = start + self.chunk_size; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (tmp, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: This type ensures that any split_at_mut on self.v is valid. + // SAFETY: The self.v contract ensures that any split_at_mut is valid. let (_, nth_back) = unsafe { tmp.split_at_mut(start) }; self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. @@ -3220,11 +3224,7 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next() { - if (self.predicate)(l, r) { - len += 1 - } else { - break; - } + if (self.predicate)(l, r) { len += 1 } else { break } } let (head, tail) = self.slice.split_at(len); self.slice = tail; @@ -3256,11 +3256,7 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next_back() { - if (self.predicate)(l, r) { - len += 1 - } else { - break; - } + if (self.predicate)(l, r) { len += 1 } else { break } } let (head, tail) = self.slice.split_at(self.slice.len() - len); self.slice = head; @@ -3315,11 +3311,7 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next() { - if (self.predicate)(l, r) { - len += 1 - } else { - break; - } + if (self.predicate)(l, r) { len += 1 } else { break } } let slice = mem::take(&mut self.slice); let (head, tail) = slice.split_at_mut(len); @@ -3352,11 +3344,7 @@ where let mut len = 1; let mut iter = self.slice.windows(2); while let Some([l, r]) = iter.next_back() { - if (self.predicate)(l, r) { - len += 1 - } else { - break; - } + if (self.predicate)(l, r) { len += 1 } else { break } } let slice = mem::take(&mut self.slice); let (head, tail) = slice.split_at_mut(slice.len() - len);