访问unordered_map时的SIGFPE

时间:2012-11-27 09:16:25

标签: c++ gcc clang libstdc++

我有unordered_map<Block, int>,其中Block是一个简单的结构,定义如下:

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;
    }
};
} 

尝试访问地图时,我确实在gdb中收到以下错误消息(g ++ 4.7.1和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; }

我的libstdc ++版本是3.4.17(即GCC 4.7的版本)

相关回溯:

#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

编辑:我认为它实际上没有什么区别 where 我调用该函数只要我给它相同的参数,但显然它确实:

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

导致错误,而只是:

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

完全正常(blocks是一个简单的vector<Block>&

5 个答案:

答案 0 :(得分:8)

除此之外:如果你的哈希函数不能抛出,那么给它一个noexcept异常规范是非常重要的,否则哈希表需要将每个元素的哈希码与元素本身一起存储(这会增加内存使用并影响性能)以便不必抛出的容器操作不必重新计算哈希码。

SIGFPE意味着除以零,并且它从回溯中发生:

    { return __num % __den; }

这可能意味着__den为零。该值来自哈希映射的桶计数,该计数不应为零。

您能确认崩溃时m._M_bucket_count是否为零?

如果是这样,那么表明你已经以某种方式破坏了地图(你是否尝试使用-D_GLIBCXX_DEBUG进行编译以打开libstdc ++调试模式检查?你试过在valgrind下运行吗?)或者那里libstdc ++代码中的一个错误。

答案 1 :(得分:4)

我有完全相同的问题。它是由memset意外应用于容器数据引起的。

答案 2 :(得分:3)

在我的情况下,由于静态init惨败导致同样的问题。 我从一个目标文件中调用了emplace方法,用于在第二个目标文件中定义的静态std :: unordered_map。由于起始数据是在BSS,因此桶数的值为零=&gt; SIGFPE。

答案 3 :(得分:1)

还将以STL代码发布有关FPE的情况。

代码使用malloc()分配std :: unordered_map。当然,这不会调用构造函数,从而导致异常状态。

答案 4 :(得分:0)

遵循其他用户在STL代码中报告导致FPE的自身情况的传统,这里是我的:

自从我们升级了编译器以来,我们在std :: map中就拥有了非常完美的代码,并且开始死于SIGFPE。事实证明,我在c ++ 11模式下使用gcc 4.8.5编译了gcc 9.2 ,这不是正常的事情-正常的gcc编译始终在gnu ++ 98模式下进行。 / p>

这导致4.8.5 gcc(其对c ++ 11的支持不完全/非官方)产生了错误的9.2 gcc,这偶尔会生成二进制文件,这些二进制文件将显示各种不相关的故障。例如,尝试调试以上SIGFPE会导致在使用-D_GLIBCXX_DEBUG编译时std :: basic_string析构函数中出现SIGSEGV,而使用-fsanitize=address检测到无关的内存损坏。

课程有两个方面:

  1. 除非您非常了解自己在做什么,否则请勿修改gcc构建系统。
  2. 有时故障可能出在编译器中(但再次,故障最终归于编译该编译器的人...)。