From e8c17ef9e34e9f5a2f812e60185f68b00f680699 Mon Sep 17 00:00:00 2001 From: hxperl Date: Tue, 15 Sep 2026 11:09:01 +0900 Subject: [PATCH] Make SliceVec::split_off honour its documented panic `SliceVec::split_off` documents "Panics ... if `at` > `self.len()`", but it split the whole backing slice rather than the initialised part, so an `at` between `len` and `capacity` was accepted. `new.len = self.len - at` then underflowed: a debug build panicked with "attempt to subtract with overflow", and a release build produced a `SliceVec` with `len == usize::MAX`. Add the same length check `ArrayVec::split_off` already performs, plus regression tests. Co-Authored-By: Claude Opus 5 (1M context) --- src/slicevec.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/slicevec.rs b/src/slicevec.rs index 9476e4d..f727285 100644 --- a/src/slicevec.rs +++ b/src/slicevec.rs @@ -559,6 +559,12 @@ impl<'s, T> SliceVec<'s, T> { /// ``` #[inline] pub fn split_off<'a>(&'a mut self, at: usize) -> SliceVec<'s, T> { + if at > self.len() { + panic!( + "SliceVec::split_off> at value {} exceeds length of {}", + at, self.len + ); + } let mut new = Self::default(); let backing: &'s mut [T] = core::mem::take(&mut self.data); let (me, other) = backing.split_at_mut(at); @@ -1122,4 +1128,23 @@ mod test { assert_eq!(buf_av, buf_ar) } + + #[test] + #[should_panic] + fn split_off_past_len_panics() { + // `at` is within the backing slice but past the vec's length, so this + // must panic the same way `ArrayVec::split_off` does. + let mut arr = [1, 2, 3, 4, 5]; + let mut sv = SliceVec::from_slice_len(&mut arr, 2); + let _ = sv.split_off(3); + } + + #[test] + fn split_off_at_len_is_allowed() { + let mut arr = [1, 2, 3, 4, 5]; + let mut sv = SliceVec::from_slice_len(&mut arr, 2); + let sv2 = sv.split_off(2); + assert_eq!(&sv[..], [1, 2]); + assert_eq!(&sv2[..], [] as [i32; 0]); + } }