rust-lang / hashbrown

Rust port of Google's SwissTable hash map
https://rust-lang.github.io/hashbrown
Apache License 2.0
2.42k stars 283 forks source link

assertion failed: buckets.is_power_of_two() #494

Closed maurerdietmar closed 9 months ago

maurerdietmar commented 9 months ago

Also working on a Tauri project, and after updating to Tauri 1.5

Maybe a bug in hashbrown? Or is it indexmap?

panicked at 'assertion failed: buckets.is_power_of_two()', /home/dietmar/.cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.14.3/src/raw/mod.rs:257:9

@http://127.0.0.1:8080/counter-example-b74547711999b1b.js:400:30 <?>.wasm-function[console_error_panic_hook::Error::new::hf5feb55b06725c0b]@[wasm code] <?>.wasm-function[console_error_panic_hook::hook_impl::h7c96ecc7b3c5151f]@[wasm code] <?>.wasm-function[console_error_panic_hook::hook::h25b47af1addaee4d]@[wasm code] <?>.wasm-function[core::ops::function::Fn::call::h88a79ee5b48a7a38]@[wasm code] <?>.wasm-function[std::panicking::rust_panic_with_hook::hf80024f269e2af44]@[wasm code] <?>.wasm-function[std::panicking::begin_panic_handler::{{closure}}::h4f7ec628c37e1d94]@[wasm code] <?>.wasm-function[std::sys_common::backtrace::__rust_end_short_backtrace::hb367ee3be27c5afc]@[wasm code] <?>.wasm-function[rust_begin_unwind]@[wasm code] <?>.wasm-function[core::panicking::panic_fmt::h92300abd4d44cfd4]@[wasm code] <?>.wasm-function[core::panicking::panic::ha477cdc2028ca479]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::TableLayout::calculate_layout_for::hadc3e4935df9baa8]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::new_uninitialized::h6e0f5a302c7f0d39]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::fallible_with_capacity::h2068887a91cc2fe0]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::prepare_resize::h3fdb1508d5f4608d]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTable<T,A>::reserve_rehash::h0302961577fc0289]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTable<T,A>::reserve::h5ea094095d929b83]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTable<T,A>::find_or_find_insert_slot::h14a4c35b86e4c531]@[wasm code] <?>.wasm-function[indexmap::map::core::raw::<impl indexmap::map::core::IndexMapCore<K,V>>::find_or_insert::hb9c92f15f2e673ca]@[wasm code] <?>.wasm-function[indexmap::map::core::IndexMapCore<K,V>::insert_full::h661d5b2b8f5f0e85]@[wasm code] <?>.wasm-function[indexmap::map::IndexMap<K,V,S>::insert_full::h91ac0d6dcdaf98fe]@[wasm code] <?>.wasm-function[indexmap::map::IndexMap<K,V,S>::insert::h879d37aa739f0f9d]@[wasm code] <?>.wasm-function[<indexmap::map::IndexMap<K,V,S> as core::iter::traits::collect::Extend<(K,V)>>::extend::{{closure}}::hc510b28f295da962]@[wasm code] <?>.wasm-function[core::iter::traits::iterator::Iterator::for_each::call::{{closure}}::h2fcf08415e7c17c3]@[wasm code] <?>.wasm-function[core::iter::adapters::map::map_fold::{{closure}}::h900d7fff744c2d72]@[wasm code] <?>.wasm-function[core::iter::adapters::map::map_fold::{{closure}}::h9194ae70e568eb3e]@[wasm code] <?>.wasm-function[core::iter::traits::iterator::Iterator::fold::h8d3b6b310e1a4677]@[wasm code] <?>.wasm-function[<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold::h17364331b999d76d]@[wasm code] <?>.wasm-function[<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold::haf35c194f0507e89]@[wasm code] <?>.wasm-function[core::iter::traits::iterator::Iterator::for_each::hb9be6a715efad007]@[wasm code] <?>.wasm-function[<indexmap::map::IndexMap<K,V,S> as core::iter::traits::collect::Extend<(K,V)>>::extend::h24e5cc3dc563d1f1]@[wasm code] <?>.wasm-function[<indexmap::map::IndexMap<K,V,S> as core::iter::traits::collect::FromIterator<(K,V)>>::from_iter::h953654f183705cb3]@[wasm code] <?>.wasm-function[<indexmap::set::IndexSet<T,S> as core::iter::traits::collect::FromIterator>::from_iter::ha504800c43161641]@[wasm code] <?>.wasm-function[core::iter::traits::iterator::Iterator::collect::had7fa03e1eecdcdb]@[wasm code] <?>.wasm-function[<yew::html::classes::Classes as core::convert::From<&str>>::from::hce3c514f4c256e95]@[wasm code] ...

Amanieu commented 9 months ago

I don't understand how this assert can trigger when this one in its caller didn't.

maurerdietmar commented 9 months ago

I don't understand how this assert can trigger when this one in its caller didn't.

Maybe the compiler optimize it away (or a compiler bug)?

maurerdietmar commented 9 months ago

Here is a different trace:

panicked at 'assertion failed: buckets.is_power_of_two()', /home/dietmar/.cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.14.3/src/raw/mod.rs:257:9

Stack:

@http://localhost:8080/frontend-76df8a485bd0132f.js:389:30 <?>.wasm-function[console_error_panic_hook::Error::new::hd269f59fea51e7d0]@[wasm code] <?>.wasm-function[console_error_panic_hook::hook_impl::h8fe6cbd0e14a2988]@[wasm code] <?>.wasm-function[console_error_panic_hook::hook::hb437b654f2cbbffb]@[wasm code] <?>.wasm-function[core::ops::function::Fn::call::h76d04d993e57483d]@[wasm code] <?>.wasm-function[std::panicking::rust_panic_with_hook::hf80024f269e2af44]@[wasm code] <?>.wasm-function[std::panicking::begin_panic_handler::{{closure}}::h4f7ec628c37e1d94]@[wasm code] <?>.wasm-function[std::sys_common::backtrace::__rust_end_short_backtrace::hb367ee3be27c5afc]@[wasm code] <?>.wasm-function[rust_begin_unwind]@[wasm code] <?>.wasm-function[core::panicking::panic_fmt::h92300abd4d44cfd4]@[wasm code] <?>.wasm-function[core::panicking::panic::ha477cdc2028ca479]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::TableLayout::calculate_layout_for::he8284f16a3559ecf]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::allocation_info::hf96686923229b007]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::free_buckets::h07029bb9325efbf3]@[wasm code] <?>.wasm-function[hashbrown::raw::inner::RawTableInner::drop_inner_table::h3f22bf028659cee1]@[wasm code] <?>.wasm-function[<hashbrown::raw::inner::RawTable<T,A> as core::ops::drop::Drop>::drop::h39a2b2572ca1fb23]@[wasm code] <?>.wasm-function[core::ptr::drop_in_place<hashbrown::raw::inner::RawTable>::hcc6a91138ea21974]@[wasm code] <?>.wasm-function[core::ptr::drop_in_place<indexmap::map::core::IndexMapCore<implicit_clone::unsync::string::IString,(implicit_clone::unsync::string::IString,yew::virtual_dom::ApplyAttributeAs)>>::h27ebafe8c02aa260]@[wasm code] <?>.wasm-function[core::ptr::drop_in_place<indexmap::map::IndexMap<implicit_clone::unsync::string::IString,(implicit_clone::unsync::string::IString,yew::virtual_dom::ApplyAttributeAs)>>::h59f63bf27df913ff]@[wasm code] <?>.wasm-function[core::ptr::drop_in_place::h0b000634777f063b]@[wasm code]

Amanieu commented 9 months ago

I'm pretty sure this isn't an issue with hashbrown, all these cases should be unreachable. Maybe you have some memory corruption somewhere? Use after free?

maurerdietmar commented 9 months ago

To debug, I added the following code:

    fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> {
        if !buckets.is_power_of_two() {
            let bits = buckets.count_ones();
            panic!("BUCKETS {} {}", buckets, bits);
        }

        debug_assert!(buckets.is_power_of_two());

This prints:

panicked at 'BUCKETS 8 14', /home/dietmar/.cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.14.3/src/raw/mod.rs:259:13

So it seems that count_ones() returns total nonsense!

Does not really look like a memory corruption, because the printed value is OK.

maurerdietmar commented 9 months ago

It works if I replace the tests with:

debug_assert!(slow_is_power_of_two(buckets));

Where slow_is_power_of_two is:

fn slow_is_power_of_two(v: usize) -> bool {
    match v {
        0b1|0b10|0b100|0b1000|0b10000|0b100000|0b1000000|0b10000000 => true,
        0b100000000| 0b1000000000| 0b10000000000| 0b100000000000 | 0b1000000000000| 0b10000000000000| 0b100000000000000| 0b1000000000000000 => true,
        _ => false,
    }
}
Amanieu commented 9 months ago

This seems to be a bug in rustc or in the wasm runtime you are using. You should open an issue there. If possible, try to create a minimal reproducer (using #[inline(never)] to avoid constant propagation).

maurerdietmar commented 9 months ago

OK. Many thanks for your help!