Skip to content

Fix allocator leak when consuming an unallocated table - #751

Merged
clarfonthey merged 1 commit into
rust-lang:mainfrom
xacrimon:fix-empty-into-iter-alloc-leak
Sep 24, 2026
Merged

clarfonthey merged 1 commit into
rust-lang:mainfrom
xacrimon:fix-empty-into-iter-alloc-leak

Conversation

@xacrimon

@xacrimon xacrimon commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RawTable::into_allocation returns None when the table is the empty singleton (it never allocated), and then calls mem::forget(self). The allocator is only moved out on the allocated path, so on the empty path it is forgotten along with the table.

Any allocator with a non-trivial Drop is leaked whenever an unallocated HashMap/HashSet/HashTable is consumed via into_iter (or into_par_iter, which goes through the same function). For example, an allocator holding an Rc/Arc loses one strong count per consumed empty table.

#439 fixed the same leak for tables that had allocated, but the non-allocated path still does not drop the allocator.

Fix

Wrap self in ManuallyDrop and read the allocator out unconditionally. It is returned alongside the allocation when there is one, and dropped otherwise.

Testing

  • Added test_hashmap_into_iter_unallocated_drops_allocator, which fails before this change (allocator refcount stays at 1) and passes after.
  • cargo test --all-targets, cargo test --features rayon,serde,raw-entry, and cargo +nightly test --features nightly,rayon pass.
  • cargo miri test --lib into_iter passes with leak checking enabled.

@xacrimon

Copy link
Copy Markdown
Contributor Author

CI is currently failing because of allocator_api being partially stabilized and this project not pinning a nightly toolchain, nothing in my PR. I blame @nia-e :)

@clarfonthey

clarfonthey commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

I'll take a look at fixing CI on another branch; you can rebase on that once I fix it. I think there are a few issues at play.

@clarfonthey

Copy link
Copy Markdown
Contributor

Yeah, okay, you were right that it's just the allocator_api2 feature. That should be merged soon.

`RawTable::into_allocation` returned `None` for the empty singleton and
then called `mem::forget(self)`, which also forgot the allocator. Any
allocator with a non-trivial `Drop` (e.g. one holding an `Rc`/`Arc`) was
leaked when an unallocated `HashMap`/`HashSet`/`HashTable` was consumed
via `into_iter` or `into_par_iter`.

Move the allocator out unconditionally so it is dropped when there is no
allocation to hand back.
@xacrimon
xacrimon force-pushed the fix-empty-into-iter-alloc-leak branch from 730e9a2 to 1e87e1f Compare September 24, 2026 11:11
@xacrimon

Copy link
Copy Markdown
Contributor Author

:) rebased, I'd consider this ready for review now. thanks!

@clarfonthey

Copy link
Copy Markdown
Contributor

Yeah, this looks very reasonable to me. Thank you!

@clarfonthey
clarfonthey added this pull request to the merge queue Sep 24, 2026
Merged via the queue into rust-lang:main with commit 7109e3a Sep 24, 2026
26 checks passed
@xacrimon

Copy link
Copy Markdown
Contributor Author

any chance we might get a point release reasonably soon?

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