Skip to content

fix: keep LinkedList consistent when an element's drop panics - #124

Merged
awolverp merged 2 commits into
awolverp:mainfrom
greenclaw:fix/linked-list-drop-panic
Oct 29, 2026
Merged

awolverp merged 2 commits into
awolverp:mainfrom
greenclaw:fix/linked-list-drop-panic

Conversation

@greenclaw

Copy link
Copy Markdown
Contributor

LinkedList::drop_nodes called ptr::drop_in_place on an element before decrementing len. If that destructor panics, len stays one too high, and DropGuard::drop (which runs drop_nodes again while unwinding) walks one node too far and drops the sentinel as if it were an element. The sentinel is also never freed on that path, although the comment says it is.

This can't happen from Python today: the LRU stores Handles, and dropping their Py objects only decrefs and never panics. It is a latent bug in the generic LinkedList<T>.

I found it by running the module under Miri, which reports it deterministically:

error: Undefined Behavior: constructing invalid value of type &mut …Bomb: encountered a dangling reference (going beyond the bounds of its allocation)
   --> src/internal/linked_list.rs:224:36

Without Miri the same test may pass (here it did on its own and aborted the test binary when run with other tests), because what happens past the sentinel depends on whatever memory is there.

Change

  • drop_nodes moves the element out, recycles the node and decrements len first, and drops the element last, so a panic leaves the list consistent.
  • DropGuard frees the free list and the sentinel on both the normal and the panic path; LinkedList::drop just runs drop_nodes under the guard.

Test

A Rust unit test in linked_list.rs: six elements, the third one panics on drop, and the list is dropped inside catch_unwind.

  • cargo test --no-default-features --lib: passes before and after on my machine (the UB is silent here).
  • cargo +nightly miri test --no-default-features --lib (with PYO3_PYTHON set): UB at linked_list.rs:224 before; clean after, also with -Zmiri-tree-borrows and -Zmiri-strict-provenance, with no leaks reported.
  • Python suite unchanged (fork CI).

The project's CI doesn't run cargo test yet. If it's useful, I can send a small separate job for cargo test and Miri; in my fork the whole Miri job takes about a minute.

drop_nodes dropped the element before decrementing len, so a panicking
destructor left len one too high and the drop guard then dropped the
sentinel as an element. The sentinel was also leaked on that path. Move the
element out and recycle the node first, and free the free list and the
sentinel from the guard on both paths.
@awolverp
awolverp merged commit 414682a into awolverp:main Oct 29, 2026
11 of 12 checks passed
@greenclaw
greenclaw deleted the fix/linked-list-drop-panic branch October 29, 2026 15:39
greenclaw added a commit to greenclaw/cachebox that referenced this pull request Oct 29, 2026
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.

2 participants