Skip to content

Commit 7919e42

Browse files
committed
Fix slice::ChunksMut aliasing
1 parent 5f98537 commit 7919e42

File tree

2 files changed

+143
-72
lines changed

2 files changed

+143
-72
lines changed

library/core/src/slice/iter.rs

+99-72
Original file line numberDiff line numberDiff line change
@@ -1629,14 +1629,15 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> {
16291629
#[stable(feature = "rust1", since = "1.0.0")]
16301630
#[must_use = "iterators are lazy and do nothing unless consumed"]
16311631
pub struct ChunksMut<'a, T: 'a> {
1632-
v: &'a mut [T],
1632+
v: *mut [T],
16331633
chunk_size: usize,
1634+
_marker: PhantomData<&'a mut T>,
16341635
}
16351636

16361637
impl<'a, T: 'a> ChunksMut<'a, T> {
16371638
#[inline]
16381639
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
1639-
Self { v: slice, chunk_size: size }
1640+
Self { v: slice, chunk_size: size, _marker: PhantomData }
16401641
}
16411642
}
16421643

@@ -1650,10 +1651,11 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16501651
None
16511652
} else {
16521653
let sz = cmp::min(self.v.len(), self.chunk_size);
1653-
let tmp = mem::replace(&mut self.v, &mut []);
1654-
let (head, tail) = tmp.split_at_mut(sz);
1654+
// SAFETY: sz cannot exceed the slice length based on the calculation above
1655+
let (head, tail) = unsafe { self.v.split_at_mut(sz) };
16551656
self.v = tail;
1656-
Some(head)
1657+
// SAFETY: Nothing points to or will point to the contents of this slice
1658+
Some(unsafe { &mut *head })
16571659
}
16581660
}
16591661

@@ -1685,11 +1687,13 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16851687
Some(sum) => cmp::min(self.v.len(), sum),
16861688
None => self.v.len(),
16871689
};
1688-
let tmp = mem::replace(&mut self.v, &mut []);
1689-
let (head, tail) = tmp.split_at_mut(end);
1690-
let (_, nth) = head.split_at_mut(start);
1690+
// SAFETY: end is inbounds because we compared above against self.v.len()
1691+
let (head, tail) = unsafe { self.v.split_at_mut(end) };
1692+
// SAFETY: start is inbounds because
1693+
let (_, nth) = unsafe { head.split_at_mut(start) };
16911694
self.v = tail;
1692-
Some(nth)
1695+
// SAFETY: Nothing points to or will point to the contents of this slice
1696+
Some(unsafe { &mut *nth })
16931697
}
16941698
}
16951699

@@ -1699,7 +1703,8 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16991703
None
17001704
} else {
17011705
let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
1702-
Some(&mut self.v[start..])
1706+
// SAFETY: Nothing points to or will point to the contents of this slice
1707+
Some(unsafe { &mut *self.v.get_unchecked_mut(start..) })
17031708
}
17041709
}
17051710

@@ -1727,12 +1732,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
17271732
} else {
17281733
let remainder = self.v.len() % self.chunk_size;
17291734
let sz = if remainder != 0 { remainder } else { self.chunk_size };
1730-
let tmp = mem::replace(&mut self.v, &mut []);
1731-
let tmp_len = tmp.len();
1735+
let len = self.v.len();
17321736
// SAFETY: Similar to `Chunks::next_back`
1733-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
1737+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
17341738
self.v = head;
1735-
Some(tail)
1739+
// SAFETY: Nothing points to or will point to the contents of this slice
1740+
Some(unsafe { &mut *tail })
17361741
}
17371742
}
17381743

@@ -1748,10 +1753,12 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
17481753
Some(res) => cmp::min(self.v.len(), res),
17491754
None => self.v.len(),
17501755
};
1751-
let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
1752-
let (head, nth_back) = temp.split_at_mut(start);
1756+
// SAFETY: end is inbounds because we compared above against self.v.len()
1757+
let (temp, _tail) = unsafe { self.v.split_at_mut(end) };
1758+
let (head, nth_back) = unsafe { temp.split_at_mut(start) };
17531759
self.v = head;
1754-
Some(nth_back)
1760+
// SAFETY: Nothing points to or will point to the contents of this slice
1761+
Some(unsafe { &mut *nth_back })
17551762
}
17561763
}
17571764
}
@@ -1957,9 +1964,10 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> {
19571964
#[stable(feature = "chunks_exact", since = "1.31.0")]
19581965
#[must_use = "iterators are lazy and do nothing unless consumed"]
19591966
pub struct ChunksExactMut<'a, T: 'a> {
1960-
v: &'a mut [T],
1961-
rem: &'a mut [T],
1967+
v: *mut [T],
1968+
rem: &'a mut [T], // The iterator never yields from here, so this can be unique
19621969
chunk_size: usize,
1970+
_marker: PhantomData<&'a mut T>,
19631971
}
19641972

19651973
impl<'a, T> ChunksExactMut<'a, T> {
@@ -1969,7 +1977,7 @@ impl<'a, T> ChunksExactMut<'a, T> {
19691977
let fst_len = slice.len() - rem;
19701978
// SAFETY: 0 <= fst_len <= slice.len() by construction above
19711979
let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) };
1972-
Self { v: fst, rem: snd, chunk_size }
1980+
Self { v: fst, rem: snd, chunk_size, _marker: PhantomData }
19731981
}
19741982

19751983
/// 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> {
19911999
if self.v.len() < self.chunk_size {
19922000
None
19932001
} else {
1994-
let tmp = mem::replace(&mut self.v, &mut []);
1995-
let (head, tail) = tmp.split_at_mut(self.chunk_size);
2002+
// SAFETY: self.chunk_size is inbounds because we compared above against self.v.len()
2003+
let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
19962004
self.v = tail;
1997-
Some(head)
2005+
// SAFETY: Nothing points to or will point to the contents of this slice
2006+
Some(unsafe { &mut *head })
19982007
}
19992008
}
20002009

@@ -2016,8 +2025,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
20162025
self.v = &mut [];
20172026
None
20182027
} else {
2019-
let tmp = mem::replace(&mut self.v, &mut []);
2020-
let (_, snd) = tmp.split_at_mut(start);
2028+
let (_, snd) = unsafe { self.v.split_at_mut(start) };
20212029
self.v = snd;
20222030
self.next()
20232031
}
@@ -2042,11 +2050,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
20422050
if self.v.len() < self.chunk_size {
20432051
None
20442052
} else {
2045-
let tmp = mem::replace(&mut self.v, &mut []);
2046-
let tmp_len = tmp.len();
2047-
let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
2053+
// SAFETY: This subtraction is inbounds because of the check above
2054+
let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) };
20482055
self.v = head;
2049-
Some(tail)
2056+
// SAFETY: Nothing points to or will point to the contents of this slice
2057+
Some(unsafe { &mut *tail })
20502058
}
20512059
}
20522060

@@ -2059,10 +2067,11 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
20592067
} else {
20602068
let start = (len - 1 - n) * self.chunk_size;
20612069
let end = start + self.chunk_size;
2062-
let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
2063-
let (head, nth_back) = temp.split_at_mut(start);
2070+
let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) };
2071+
let (head, nth_back) = unsafe { temp.split_at_mut(start) };
20642072
self.v = head;
2065-
Some(nth_back)
2073+
// SAFETY: Nothing points to or will point to the contents of this slice
2074+
Some(unsafe { &mut *nth_back })
20662075
}
20672076
}
20682077
}
@@ -2646,14 +2655,15 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> {
26462655
#[stable(feature = "rchunks", since = "1.31.0")]
26472656
#[must_use = "iterators are lazy and do nothing unless consumed"]
26482657
pub struct RChunksMut<'a, T: 'a> {
2649-
v: &'a mut [T],
2658+
v: *mut [T],
26502659
chunk_size: usize,
2660+
_marker: PhantomData<&'a mut T>,
26512661
}
26522662

26532663
impl<'a, T: 'a> RChunksMut<'a, T> {
26542664
#[inline]
26552665
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
2656-
Self { v: slice, chunk_size: size }
2666+
Self { v: slice, chunk_size: size, _marker: PhantomData }
26572667
}
26582668
}
26592669

@@ -2667,16 +2677,16 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
26672677
None
26682678
} else {
26692679
let sz = cmp::min(self.v.len(), self.chunk_size);
2670-
let tmp = mem::replace(&mut self.v, &mut []);
2671-
let tmp_len = tmp.len();
2680+
let len = self.v.len();
26722681
// SAFETY: split_at_mut_unchecked just requires the argument be less
26732682
// than the length. This could only happen if the expression
2674-
// `tmp_len - sz` overflows. This could only happen if `sz >
2675-
// tmp_len`, which is impossible as we initialize it as the `min` of
2676-
// `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
2677-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
2683+
// `len - sz` overflows. This could only happen if `sz >
2684+
// len`, which is impossible as we initialize it as the `min` of
2685+
// `self.v.len()` (e.g. `len`) and `self.chunk_size`.
2686+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
26782687
self.v = head;
2679-
Some(tail)
2688+
// SAFETY: Nothing points to or will point to the contents of this slice
2689+
Some(unsafe { &mut *tail })
26802690
}
26812691
}
26822692

@@ -2710,11 +2720,11 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
27102720
Some(sum) => sum,
27112721
None => 0,
27122722
};
2713-
let tmp = mem::replace(&mut self.v, &mut []);
2714-
let (head, tail) = tmp.split_at_mut(start);
2715-
let (nth, _) = tail.split_at_mut(end - start);
2723+
let (head, tail) = unsafe { self.v.split_at_mut(start) };
2724+
let (nth, _) = unsafe { tail.split_at_mut(end - start) };
27162725
self.v = head;
2717-
Some(nth)
2726+
// SAFETY: Nothing points to or will point to the contents of this slice
2727+
Some(unsafe { &mut *nth })
27182728
}
27192729
}
27202730

@@ -2725,7 +2735,8 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
27252735
} else {
27262736
let rem = self.v.len() % self.chunk_size;
27272737
let end = if rem == 0 { self.chunk_size } else { rem };
2728-
Some(&mut self.v[0..end])
2738+
// SAFETY: Nothing points to or will point to the contents of this slice
2739+
Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) })
27292740
}
27302741
}
27312742

@@ -2750,11 +2761,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
27502761
} else {
27512762
let remainder = self.v.len() % self.chunk_size;
27522763
let sz = if remainder != 0 { remainder } else { self.chunk_size };
2753-
let tmp = mem::replace(&mut self.v, &mut []);
27542764
// SAFETY: Similar to `Chunks::next_back`
2755-
let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) };
2765+
let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) };
27562766
self.v = tail;
2757-
Some(head)
2767+
// SAFETY: Nothing points to or will point to the contents of this slice
2768+
Some(unsafe { &mut *head })
27582769
}
27592770
}
27602771

@@ -2769,10 +2780,11 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
27692780
let offset_from_end = (len - 1 - n) * self.chunk_size;
27702781
let end = self.v.len() - offset_from_end;
27712782
let start = end.saturating_sub(self.chunk_size);
2772-
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
2773-
let (_, nth_back) = tmp.split_at_mut(start);
2783+
let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
2784+
let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
27742785
self.v = tail;
2775-
Some(nth_back)
2786+
// SAFETY: Nothing points to or will point to the contents of this slice
2787+
Some(unsafe { &mut *nth_back })
27762788
}
27772789
}
27782790
}
@@ -2898,8 +2910,7 @@ impl<'a, T> Iterator for RChunksExact<'a, T> {
28982910
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
28992911
let end = self.v.len() - idx * self.chunk_size;
29002912
let start = end - self.chunk_size;
2901-
// SAFETY:
2902-
// SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`.
2913+
// SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
29032914
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
29042915
}
29052916
}
@@ -2982,7 +2993,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> {
29822993
#[stable(feature = "rchunks", since = "1.31.0")]
29832994
#[must_use = "iterators are lazy and do nothing unless consumed"]
29842995
pub struct RChunksExactMut<'a, T: 'a> {
2985-
v: &'a mut [T],
2996+
v: *mut [T],
29862997
rem: &'a mut [T],
29872998
chunk_size: usize,
29882999
}
@@ -3015,11 +3026,11 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30153026
if self.v.len() < self.chunk_size {
30163027
None
30173028
} else {
3018-
let tmp = mem::replace(&mut self.v, &mut []);
3019-
let tmp_len = tmp.len();
3020-
let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
3029+
let len = self.v.len();
3030+
let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) };
30213031
self.v = head;
3022-
Some(tail)
3032+
// SAFETY: Nothing points to or will point to the contents of this slice
3033+
Some(unsafe { &mut *tail })
30233034
}
30243035
}
30253036

@@ -3041,9 +3052,8 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30413052
self.v = &mut [];
30423053
None
30433054
} else {
3044-
let tmp = mem::replace(&mut self.v, &mut []);
3045-
let tmp_len = tmp.len();
3046-
let (fst, _) = tmp.split_at_mut(tmp_len - end);
3055+
let len = self.v.len();
3056+
let (fst, _) = unsafe { self.v.split_at_mut(len - end) };
30473057
self.v = fst;
30483058
self.next()
30493059
}
@@ -3069,10 +3079,10 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
30693079
if self.v.len() < self.chunk_size {
30703080
None
30713081
} else {
3072-
let tmp = mem::replace(&mut self.v, &mut []);
3073-
let (head, tail) = tmp.split_at_mut(self.chunk_size);
3082+
let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
30743083
self.v = tail;
3075-
Some(head)
3084+
// SAFETY: Nothing points to or will point to the contents of this slice
3085+
Some(unsafe { &mut *head })
30763086
}
30773087
}
30783088

@@ -3088,10 +3098,11 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
30883098
let offset = (len - n) * self.chunk_size;
30893099
let start = self.v.len() - offset;
30903100
let end = start + self.chunk_size;
3091-
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
3092-
let (_, nth_back) = tmp.split_at_mut(start);
3101+
let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
3102+
let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
30933103
self.v = tail;
3094-
Some(nth_back)
3104+
// SAFETY: Nothing points to or will point to the contents of this slice
3105+
Some(unsafe { &mut *nth_back })
30953106
}
30963107
}
30973108
}
@@ -3174,7 +3185,11 @@ where
31743185
let mut len = 1;
31753186
let mut iter = self.slice.windows(2);
31763187
while let Some([l, r]) = iter.next() {
3177-
if (self.predicate)(l, r) { len += 1 } else { break }
3188+
if (self.predicate)(l, r) {
3189+
len += 1
3190+
} else {
3191+
break;
3192+
}
31783193
}
31793194
let (head, tail) = self.slice.split_at(len);
31803195
self.slice = tail;
@@ -3206,7 +3221,11 @@ where
32063221
let mut len = 1;
32073222
let mut iter = self.slice.windows(2);
32083223
while let Some([l, r]) = iter.next_back() {
3209-
if (self.predicate)(l, r) { len += 1 } else { break }
3224+
if (self.predicate)(l, r) {
3225+
len += 1
3226+
} else {
3227+
break;
3228+
}
32103229
}
32113230
let (head, tail) = self.slice.split_at(self.slice.len() - len);
32123231
self.slice = head;
@@ -3261,7 +3280,11 @@ where
32613280
let mut len = 1;
32623281
let mut iter = self.slice.windows(2);
32633282
while let Some([l, r]) = iter.next() {
3264-
if (self.predicate)(l, r) { len += 1 } else { break }
3283+
if (self.predicate)(l, r) {
3284+
len += 1
3285+
} else {
3286+
break;
3287+
}
32653288
}
32663289
let slice = mem::take(&mut self.slice);
32673290
let (head, tail) = slice.split_at_mut(len);
@@ -3294,7 +3317,11 @@ where
32943317
let mut len = 1;
32953318
let mut iter = self.slice.windows(2);
32963319
while let Some([l, r]) = iter.next_back() {
3297-
if (self.predicate)(l, r) { len += 1 } else { break }
3320+
if (self.predicate)(l, r) {
3321+
len += 1
3322+
} else {
3323+
break;
3324+
}
32983325
}
32993326
let slice = mem::take(&mut self.slice);
33003327
let (head, tail) = slice.split_at_mut(slice.len() - len);

0 commit comments

Comments
 (0)