Skip to content

SliceVec::split_off does not panic when at > len, and underflows its length - #228

Open
hxperl wants to merge 1 commit into
Lokathor:mainfrom
hxperl:fix-slicevec-split-off-bounds
Open

hxperl wants to merge 1 commit into
Lokathor:mainfrom
hxperl:fix-slicevec-split-off-bounds

Conversation

@hxperl

@hxperl hxperl commented Sep 15, 2026

Copy link
Copy Markdown

SliceVec::split_off documents ## Panics * if at > self.len(), but it never checks at against self.len(). It takes the whole backing slice and splits that, so split_at_mut only rejects at > capacity. For any at in (len, capacity], self.len - at underflows.

ArrayVec::split_off and TinyVec::split_off both do perform the check; SliceVec is the odd one out.

Reproduction

On main (e343bbb, v1.13.3):

let mut arr = [1, 2, 3, 4, 5];
let mut sv = SliceVec::from_slice_len(&mut arr, 2); // len 2, capacity 5
let sv2 = sv.split_off(3);                          // docs say: panics

Debug: it panics, but on the underflow — attempt to subtract with overflow at slicevec.rs:565, pointing at tinyvec's internals rather than the caller's mistake.

Release (cargo test --release, overflow checks off): no panic at all.

no panic. self.len()=3 self.capacity()=3
new.len()=18446744073709551615 new.capacity()=2

The returned SliceVec has len == usize::MAX over a 2-element slice, so the next &sv2[..] panics inside Deref. And the receiver silently grew from 2 to 3, handing back an element nobody pushed.

The change

The same guard ArrayVec::split_off already uses, worded the same way, plus two regression tests (split_off_past_len_panics, and split_off_at_len_is_allowed to pin the off-by-one). The doc comment becomes true as written, so it is unchanged.

This is a behaviour change and it is yours to call. Code that "worked" in release now panics. I think that is right given what it produced instead, but if you would rather have a debug assertion, or a try_split_off shape, say which and I will redo it.

Verified on macOS arm64, rustc 1.98.1: cargo test with alloc,std,grab_spare_slice,latest_stable_rust all green, and cargo test --release --lib is the one that matters — split_off_past_len_panics fails on main and passes here. cargo fmt --check clean. I did not run --all-features or the debugger_visualizer test.

No changelog.md entry — the history suggests those are written at release time, but glad to add one.

`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) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants