Skip to content

Fix incorrect length if a hasher panics during rehash#710

Merged
Amanieu merged 2 commits intorust-lang:masterfrom
Amanieu:fix-rehash-unwind
Apr 6, 2026
Merged

Fix incorrect length if a hasher panics during rehash#710
Amanieu merged 2 commits intorust-lang:masterfrom
Amanieu:fix-rehash-unwind

Conversation

@Amanieu
Copy link
Copy Markdown
Member

@Amanieu Amanieu commented Apr 6, 2026

If the user-provided hasher panics during an in-place rehash and the key/value types do not need to be dropped (according to core::mem::needs_drop) then the length field of the hash map may not be updated correctly. The map will appear to have more elements than it actually does, which will cause iterators (which blindly trust the length) to read past the end of the map, potentially reading uninitialized memory.

This issue was discovered by @lopopolo and @codex and the reproducer that they produced has been adapted an included in this PR.

@clarfonthey
Copy link
Copy Markdown
Contributor

Just to double-check: this is only a length mismatch, right, and not the potential to drop stuff twice? Good find either way.

@Amanieu
Copy link
Copy Markdown
Member Author

Amanieu commented Apr 6, 2026

This bug only happens if the mem::needs_drop::<T>() == false. So there is nothing to drop.

The problem is that RawIter relies on the length being accurate and in this case will continue reading past the end of the control byte array because the length is greater than the number of full entries in the control bytes.

@clarfonthey
Copy link
Copy Markdown
Contributor

clarfonthey commented Apr 6, 2026

Ah, yeah, that makes sense. I mostly only ask to see if we could add some test that would be able to detect that under miri if the code regressed, and I'm not sure the existing one does.

Although, I guess that it doesn't really matter if they don't need to be dropped, since it would probably be fine to read them more than necessary. And the control is still limited by the mask, which from my understanding, would still be correct here.

@cuviper
Copy link
Copy Markdown
Member

cuviper commented Apr 6, 2026

Miri seems to be hanging on this test in CI...

@clarfonthey
Copy link
Copy Markdown
Contributor

clarfonthey commented Apr 6, 2026

Was thinking, doesn't the miri run usually take a while? And no, latest commit took 1min30s: https://github.com/rust-lang/hashbrown/actions/runs/23953355374/job/69865909833

Comment thread tests/hasher_unwind.rs Outdated
Comment on lines +149 to +151
for i in 0..111 {
hashmap_reserve_survives_panicking_build_hasher_inner(i);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my system, each iteration of this takes about 15s in miri, which tracks with CI's final completion time around 30min. Maybe it would suffice to try only specific first, middle, last indices, i.e. [0, 55, 110].

@Amanieu Amanieu added this pull request to the merge queue Apr 6, 2026
Merged via the queue into rust-lang:master with commit 3b6489a Apr 6, 2026
25 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 6, 2026
rust-bors Bot pushed a commit to rust-lang/rust that referenced this pull request Apr 12, 2026
Update hashbrown to 0.17

The main benefit of this update is to include one potential UB fix and one bug; relevant changelog entries:

* Fixed potential UB in `RawTableInner::fallible_with_capacity` (rust-lang/hashbrown#692)
* Fixed incorrect length if a hasher panics during rehash (rust-lang/hashbrown#710)

cc @Amanieu

Also cc @RalfJung who had also noticed the UB issue with `-Zmiri-recursive-validation`.
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.

3 participants