Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OnceMap unsound if Hash panics in such a way as to prevent HashMap/HashTable rehashing to succeed #3

Closed
steffahn opened this issue Nov 22, 2023 · 1 comment

Comments

@steffahn
Copy link

Adapted from

also relevant for context

Here’s the reproduction:

use std::{
    panic::{catch_unwind, AssertUnwindSafe},
    sync::Mutex,
};

#[derive(PartialEq, Eq, Debug)]
struct H(u32);

impl std::hash::Hash for H {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        if PANIC_ON.lock().unwrap().as_ref() == Some(&self.0) {
            panic!();
        }
        0_u32.hash(state);
    }
}

static PANIC_ON: Mutex<Option<u32>> = Mutex::new(None);

fn main() {
    let mut map = once_map::sync::OnceMap::new();
    for i in 1..=28 {
        map.insert(H(i), |k| {
            if *k == H(28) {
                String::from("Hello World!")
            } else {
                String::new()
            }
        });
    }
    for i in 1..=27 {
        map.remove(&H(i));
    }

    let hello_world = map.get(&H(28)).unwrap();

    println!("exists: {hello_world}");

    let _ = catch_unwind(AssertUnwindSafe(|| {
        *PANIC_ON.lock().unwrap() = Some(28);
        map.insert(H(1), |_| String::new());
    }));

    println!("gone: {hello_world}");
}
$ cargo run
   Compiling libc v0.2.150
   Compiling cfg-if v1.0.0
   Compiling version_check v0.9.4
   Compiling autocfg v1.1.0
   Compiling parking_lot_core v0.9.9
   Compiling smallvec v1.11.2
   Compiling scopeguard v1.2.0
   Compiling zerocopy v0.7.26
   Compiling once_cell v1.18.0
   Compiling stable_deref_trait v1.2.0
   Compiling lock_api v0.4.11
   Compiling ahash v0.8.6
   Compiling getrandom v0.2.11
   Compiling parking_lot v0.12.1
   Compiling hashbrown v0.14.2
   Compiling once_map v0.4.12
   Compiling local_playground v0.1.0 (/path/to/local_playground)
    Finished dev [unoptimized + debuginfo] target(s) in 2.06s
     Running `target/debug/local_playground`
exists: Hello World!
thread 'main' panicked at src/main.rs:12:13:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
gone: ���X���F

See also here and here in the hashbrown source-code for more information.

@a1phyr
Copy link
Owner

a1phyr commented Nov 23, 2023

Thanks for this report and this repro !

This is quite unexpected from hashbrown to be honest. I'll add code to make sure that hashing never unwind.

@a1phyr a1phyr closed this as completed in 277a5e6 Nov 23, 2023
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

No branches or pull requests

2 participants