@@ -1474,7 +1474,24 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
14741474 } else {
14751475 let remainder = self . v . len ( ) % self . chunk_size ;
14761476 let chunksz = if remainder != 0 { remainder } else { self . chunk_size } ;
1477- let ( fst, snd) = self . v . split_at ( self . v . len ( ) - chunksz) ;
1477+ // SAFETY: split_at_unchecked requires the argument be less than or
1478+ // equal to the length. This is guaranteed, but subtle: We need the
1479+ // expression `self.v.len() - sz` not to overflow, which means we
1480+ // need `sz >= tmp_len`.
1481+ //
1482+ // `sz` will always either be `self.v.len() % self.chunk_size`,
1483+ // which will always evaluate to strictly less than `self.v.len()`
1484+ // (or panic, in the case that `self.chunk_size` is zero), or it can
1485+ // be `self.chunk_size`, in the case that the length is exactly
1486+ // divisible by the chunk size.
1487+ //
1488+ // While it seems like using `self.chunk_size` in this case could
1489+ // lead to a value greater than `self.v.len()`, it cannot: if
1490+ // `self.chunk_size` were greater than `self.v.len()`, then
1491+ // `self.v.len() % self.chunk_size` would have returned non-zero
1492+ // (note that in this branch of the `if`, we already know that
1493+ // `self.v` is non-empty).
1494+ let ( fst, snd) = unsafe { self . v . split_at_unchecked ( self . v . len ( ) - chunksz) } ;
14781495 self . v = fst;
14791496 Some ( snd)
14801497 }
@@ -1639,7 +1656,26 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
16391656 let sz = if remainder != 0 { remainder } else { self . chunk_size } ;
16401657 let tmp = mem:: replace ( & mut self . v , & mut [ ] ) ;
16411658 let tmp_len = tmp. len ( ) ;
1642- let ( head, tail) = tmp. split_at_mut ( tmp_len - sz) ;
1659+ // SAFETY: split_at_unchecked requires the argument be less than or
1660+ // equal to the length. This is guaranteed, but subtle: We need the
1661+ // expression `tmp_len - sz` not to overflow, which means we need
1662+ // `sz >= tmp_len`.
1663+ //
1664+ // `sz` will always either be `tmp_or_v.len() % self.chunk_size`
1665+ // (where `tmp_or_v` is the slice that at the time was `self.v` but
1666+ // now is `tmp`, and thus `tmp_len` and `tmp_or_v.len()` are the
1667+ // same), which will always evaluate to strictly less than
1668+ // `tmp_or_v.len()` (or panic, in the case that `self.chunk_size` is
1669+ // zero), or it can be `self.chunk_size`, in the case that the
1670+ // length is exactly divisible by the chunk size.
1671+ //
1672+ // While it seems like using `self.chunk_size` in this case could
1673+ // lead to a value greater than `tmp_len`, it cannot: if
1674+ // `self.chunk_size` were greater than `tmp_len`, then
1675+ // `tmp_or_v.len() % self.chunk_size` would have returned non-zero
1676+ // (note that in this branch of the `if`, we already know that
1677+ // `self.v` is non-empty).
1678+ let ( head, tail) = unsafe { tmp. split_at_mut_unchecked ( tmp_len - sz) } ;
16431679 self . v = head;
16441680 Some ( tail)
16451681 }
@@ -2409,7 +2445,12 @@ impl<'a, T> Iterator for RChunks<'a, T> {
24092445 None
24102446 } else {
24112447 let chunksz = cmp:: min ( self . v . len ( ) , self . chunk_size ) ;
2412- let ( fst, snd) = self . v . split_at ( self . v . len ( ) - chunksz) ;
2448+ // SAFETY: split_at_unchecked just requires the argument be less
2449+ // than the length. This could only happen if the expression
2450+ // `self.v.len() - chunksz` overflows. This could only happen if
2451+ // `chunksz > self.v.len()`, which is impossible as we initialize it
2452+ // as the `min` of `self.v.len()` and `self.chunk_size`.
2453+ let ( fst, snd) = unsafe { self . v . split_at_unchecked ( self . v . len ( ) - chunksz) } ;
24132454 self . v = fst;
24142455 Some ( snd)
24152456 }
@@ -2483,7 +2524,21 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
24832524 } else {
24842525 let remainder = self . v . len ( ) % self . chunk_size ;
24852526 let chunksz = if remainder != 0 { remainder } else { self . chunk_size } ;
2486- let ( fst, snd) = self . v . split_at ( chunksz) ;
2527+ // SAFETY: split_at_unchecked requires the argument be less than or
2528+ // equal to the length. This is guaranteed, but subtle: `chunksz`
2529+ // will always either be `self.v.len() % self.chunk_size`, which
2530+ // will always evaluate to strictly less than `self.v.len()` (or
2531+ // panic, in the case that `self.chunk_size` is zero), or it can be
2532+ // `self.chunk_size`, in the case that the length is exactly
2533+ // divisible by the chunk size.
2534+ //
2535+ // While it seems like using `self.chunk_size` in this case could
2536+ // lead to a value greater than `self.v.len()`, it cannot: if
2537+ // `self.chunk_size` were greater than `self.v.len()`, then
2538+ // `self.v.len() % self.chunk_size` would return nonzero (note that
2539+ // in this branch of the `if`, we already know that `self.v` is
2540+ // non-empty).
2541+ let ( fst, snd) = unsafe { self . v . split_at_unchecked ( chunksz) } ;
24872542 self . v = snd;
24882543 Some ( fst)
24892544 }
@@ -2569,7 +2624,12 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
25692624 let sz = cmp:: min ( self . v . len ( ) , self . chunk_size ) ;
25702625 let tmp = mem:: replace ( & mut self . v , & mut [ ] ) ;
25712626 let tmp_len = tmp. len ( ) ;
2572- let ( head, tail) = tmp. split_at_mut ( tmp_len - sz) ;
2627+ // SAFETY: split_at_mut_unchecked just requires the argument be less
2628+ // than the length. This could only happen if the expression
2629+ // `tmp_len - sz` overflows. This could only happen if `sz >
2630+ // tmp_len`, which is impossible as we initialize it as the `min` of
2631+ // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
2632+ let ( head, tail) = unsafe { tmp. split_at_mut_unchecked ( tmp_len - sz) } ;
25732633 self . v = head;
25742634 Some ( tail)
25752635 }
@@ -2647,7 +2707,22 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
26472707 let remainder = self . v . len ( ) % self . chunk_size ;
26482708 let sz = if remainder != 0 { remainder } else { self . chunk_size } ;
26492709 let tmp = mem:: replace ( & mut self . v , & mut [ ] ) ;
2650- let ( head, tail) = tmp. split_at_mut ( sz) ;
2710+ // SAFETY: split_at_mut_unchecked requires the argument be less than
2711+ // or equal to the length. This is guaranteed, but subtle: `chunksz`
2712+ // will always either be `tmp_or_v.len() % self.chunk_size` (where
2713+ // `tmp_or_v` is the slice that at the time was `self.v` but now is
2714+ // `tmp`), which will always evaluate to strictly less than
2715+ // `tmp_or_v.len()` (or panic, in the case that `self.chunk_size` is
2716+ // zero), or it can be `self.chunk_size`, in the case that the
2717+ // length is exactly divisible by the chunk size.
2718+ //
2719+ // While it seems like using `self.chunk_size` in this case could
2720+ // lead to a value greater than `tmp_or_v.len()`, it cannot: if
2721+ // `self.chunk_size` were greater than `tmp_or_v.len()`, then
2722+ // `tmp_or_v.len() % self.chunk_size` would return nonzero (note
2723+ // that in this branch of the `if`, we already know that `tmp_or_v`
2724+ // is non-empty).
2725+ let ( head, tail) = unsafe { tmp. split_at_mut_unchecked ( sz) } ;
26512726 self . v = tail;
26522727 Some ( head)
26532728 }
0 commit comments