Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SIGFPE when accessing unordered_map

I have an unordered_map<Block, int> with Block being a simple struct defined as follows:

struct Block {
    size_t start;
    size_t end;

    bool operator==(const Block& b) const {
        return start == b.start && end == b.end;
    }
};

namespace std {
template<>
struct hash<Block> {
    size_t operator()(const Block& b) const {
        return b.start;
    }
};
} 

When trying to access the map, I do get the following error message in gdb (same for both g++ 4.7.1 as well as clang++ 3.1):

Program received signal SIGFPE, Arithmetic exception.
0x0000000000401e0b in std::__detail::_Mod_range_hashing::operator() (this=0x7fffffffd8e0, __num=0, __den=0)
    at /usr/include/c++/4.7/bits/hashtable_policy.h:245
245     { return __num % __den; }

My libstdc++ version is 3.4.17 (i.e. the version from GCC 4.7)

Relevant backtrace:

#0  0x0000000000401e0b in std::__detail::_Mod_range_hashing::operator() (this=0x7fffffffd8e0, __num=0, __den=0)
    at /usr/include/c++/4.7/bits/hashtable_policy.h:245
#1  0x0000000000407199 in std::__detail::_Hash_code_base<Block, std::pair<Block const, int>, std::_Select1st<std::pair<Block const, int> >, std::hash<Block>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, true>::_M_bucket_index (this=0x7fffffffd8e0, __c=0, __n=0) at /usr/include/c++/4.7/bits/hashtable_policy.h:787
#2  0x0000000000405230 in std::_Hashtable<Block, std::pair<Block const, int>, std::allocator<std::pair<Block const, int> >, std::_Select1st<std::pair<Block const, int> >, std::equal_to<Block>, std::hash<Block>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, true, false, true>::_M_bucket_index
    (this=0x7fffffffd8e0, __k=..., __c=0) at /usr/include/c++/4.7/bits/hashtable.h:466
#3  0x00000000004038de in std::__detail::_Map_base<Block, std::pair<Block const, int>, std::_Select1st<std::pair<Block const, int> >, true, std::_Hashtable<Block, std::pair<Block const, int>, std::allocator<std::pair<Block const, int> >, std::_Select1st<std::pair<Block const, int> >, std::equal_to<Block>, std::hash<Block>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, true, false, true> >::at (
    this=0x7fffffffd8e0, __k=...) at /usr/include/c++/4.7/bits/hashtable_policy.h:474
#4  0x0000000000403001 in SplicedAlignment::FindOptimalEndBlock() const::{lambda(Block const&)#1}::operator()(Block const&) const (__closure=0x7fffffffd990, block=...) at splicing.cpp:151
#5  0x00000000004040b3 in std::for_each<__gnu_cxx::__normal_iterator<Block const*, std::vector<Block, std::allocator<Block> > >, SplicedAlignment::FindOptimalEndBlock() const::{lambda(Block const&)#1}>(__gnu_cxx::__normal_iterator<Block const*, std::vector<Block, std::allocator<Block> > >, SplicedAlignment::FindOptimalEndBlock() const::{lambda(Block const&)#1}, SplicedAlignment::FindOptimalEndBlock() const::{lambda(Block const&)#1}) (__first=..., __last=..., __f=...)
    at /usr/include/c++/4.7/bits/stl_algo.h:4442

Edit: I didn't think it would actually make a difference where I call the function as long as I give it the same arguments, but apparently it does:

std::for_each(blocks.begin(), blocks.end(), [&](const Block& block) {
   map.at(block);
}

leads to the error, while just having:

const Block& block = blocks[0];
map.at(block);

works perfectly fine (blocks being a simple vector<Block>&)

like image 417
Voo Avatar asked Nov 27 '12 09:11

Voo


People also ask

How do you check if an element is in an unordered_map?

To check for the existence of a particular key in the map, the standard solution is to use the public member function find() of the ordered or the unordered map container, which returns an iterator to the key-value pair if the specified key is found, or iterator to the end of the container if the specified key is not ...

What is the complexity of find in unordered_map?

Time Complexity : O(1) on average.

Can keys of unordered map be paired?

Unordered Map does not contain a hash function for a pair like it has for int, string, etc, So if we want to hash a pair then we have to explicitly provide it with a hash function that can hash a pair.

Which is faster ordered map or unordered_map?

If you use more modern Studio like 2017 - then unordered_map much faster than ordered map.


1 Answers

Aside: if your hash function cannot throw then it's quite important to give it a noexcept exception-specification, otherwise the hash table needs to store every element's hash code alongside the element itself (which increases memory usage and affects performance) so that container operations that must not throw do not have to recalculate the hash code.

The SIGFPE implies a divide by zero and from the backtrace it happens here:

    { return __num % __den; }

which probably means __den is zero. That value comes from the hash map's bucket count, which should not be zero.

Can you confirm that when it crashes m._M_bucket_count is zero?

If so, that either indicates you've corrupted the map somehow (have you tried compiling with -D_GLIBCXX_DEBUG to turn on the libstdc++ Debug Mode checks? Have you tried running under valgrind?) or there's a bug in the libstdc++ code (which is possible, but unlikely).

Some of the other answers below give examples of how the map can be corrupted, e.g. allocating storage for it with malloc but not actually constructing an object in that storage, or overwriting the object with memset.

Another possibility is that your hash map is a global variable, and you are accessing it from the constructor of another global variable, which runs into the Static Initialization Order Fiasco. If the map is used before its constructor runs, then the bucket count will be zero.

like image 170
Jonathan Wakely Avatar answered Sep 21 '22 05:09

Jonathan Wakely