Skip to content

Fix panic-safety unsoundness in LinkedHashMap::into_iter and clear — #116 - #116

Open
tooson9010-spec wants to merge 2 commits into
contain-rs:masterfrom
tooson9010-spec:fix/into-iter-panic-safety
Open

tooson9010-spec wants to merge 2 commits into
contain-rs:masterfrom
tooson9010-spec:fix/into-iter-panic-safety

Conversation

@tooson9010-spec

@tooson9010-spec tooson9010-spec commented Aug 10, 2026 •

Copy link
Copy Markdown

Two panic-safety bugs in LinkedHashMap. Both are memory corruption triggered by
a user's Drop panicking mid-teardown.

into_iter (use-after-free, CWE-416)

into_iter frees the sentinel node and drops the internal HashMap, then commits
the ownership transfer with mem::forget(self). The HashMap owns the hasher S,
whose Drop can panic. If it panics after the sentinel is freed, mem::forget is
skipped and the original LinkedHashMap is dropped during unwinding — its
destructor follows the dangling head pointer.

Fix: wrap self in ManuallyDrop instead of relying on mem::forget(self) after the
fallible teardown. On panic the remaining nodes leak, which is fine.

clear (double-free, CWE-415)

clear frees the value nodes, running each K/V's Drop, and resets the guard links
afterwards. A value Drop that panics partway leaves the reset unrun, so self.head
still points into freed memory. The map's own destructor then walks that chain
again and frees it a second time.

Fix: reset the guard links before freeing anything. self.head is an empty list
by the time any unwind can start, so nothing gets freed twice.

Verification

Existing tests pass. Added two regression tests (catch_unwind):
into_iter_panicking_hasher_is_sound — ASAN reports heap-use-after-free without
the fix; clear_panicking_value_drop_is_sound — SIGSEGV / double-free without the
fix. Both unwind cleanly once fixed. Confirmed on 0.5.6.

tooson9010-spec and others added 2 commits August 10, 2026 16:25
…king hasher Drop)

into_iter frees the sentinel node and drops the internal HashMap, then
commits the ownership transfer with mem::forget(self). The HashMap owns the
hasher S, whose Drop is user-controlled and may panic. If it panics after
the sentinel is freed, mem::forget is skipped and the original LinkedHashMap
is dropped during unwinding, whose destructor follows the now-dangling head
pointer -- a use-after-free (CWE-416) reachable from safe Rust. Wrap self in
ManuallyDrop so the original is never dropped automatically, and add a
regression test.
…lue Drop)

clear frees the value nodes (running each K/V's user-controlled Drop) and
only afterwards resets the sentinel's guard links. If a value's Drop panics
partway through, the reset is skipped and self.head is left pointing at freed
memory; the map's own destructor then re-walks the chain during unwinding and
frees it again -- a double-free (CWE-415) reachable from safe Rust. Detach the
guard links before freeing so unwinding leaves an empty, self-consistent list,
and add a regression test.
@tooson9010-spec tooson9010-spec changed the title Fix panic-safety unsoundness in LinkedHashMap::into_iter Fix panic-safety unsoundness in LinkedHashMap::into_iter and clear — #116 Sep 4, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant