Fix panic-safety in Drain::clear_remain (double-free / UAF on panicking Drop) - #1
Open
tooson9010-spec wants to merge 2 commits into
Open
Conversation
…ng Drop) clear_remain() dropped the remaining element before advancing remain.start. If the element's Drop panics, the cursor is left stale; since Splice owns a Drain field, unwinding from Splice::drop drops that Drain, whose Drop calls clear_remain again and drops the same element a second time -- a double-free (CWE-415) / use-after-free (CWE-416) reachable from safe Rust via Vec::splice. Advance the cursor before running the destructor, and add a regression test.
Remove commented-out old code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Drain::clear_remainis not panic-safe. It runs the element destructor before advancing theremaincursor, so if an element'sDroppanics, the cursor is left stale. BecauseSpliceowns aDrainfield, unwinding fromSplice::dropdrops thatDrain, whoseDropcallsclear_remainagain and drops the same element a second time — a double-free (CWE-415) / use-after-free (CWE-416) reachable from safe Rust viaVec::splice.Fix
Advance
remain.startto mark the range consumed before running the destructor. Once the cursor is advanced, a panicking drop can no longer leave the same element visible to the re-entrantDrain::drop→clear_remain. (The raw pointer is taken first so the&mut selfborrow ends before the cursor is updated.)Verification
Existing tests still pass. The added
vec_splice_panicking_drop_is_soundtest splices out an element whoseDroppanics, undercatch_unwind, then drops the vector: under AddressSanitizer the original code reports a heap-use-after-free, and with the fix it runs clean with each element dropped exactly once. Confirmed on 0.0.5.Note: a separate pre-existing issue in the same function
While preparing this fix I noticed
clear_remainpassesas_mut_slice().as_mut_ptr()(the first element) todrop_in_placewhile marking the whole range consumed. Ifremainever holds more than one element, this looks like it would drop only the first and leak the rest. It's independent of the panic-safety fix, so I left it out of this PR — happy to address it separately, or you may prefer to fix it your own way.