SIGFPE при доступе к unordered_map

у меня есть 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

Редактировать: я не думал, что это на самом деле будет иметь значение где Я вызываю функцию до тех пор, пока даю ей те же аргументы, но, очевидно, это так:

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

приводит к ошибке, при этом просто имея:

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

отлично работает (blocks быть простым vector<Block>&)

10

Решение

Кроме того: если ваша хеш-функция не может выдать, очень важно дать ей noexcept спецификация исключения, в противном случае хеш-таблица должна хранить хеш-код каждого элемента вместе с самим элементом (что увеличивает использование памяти и влияет на производительность), так что контейнерные операции, которые не должны генерироваться, не должны пересчитывать хеш-код.

SIGFPE подразумевает деление на ноль, и из обратной трассировки это происходит здесь:

    { return __num % __den; }

что, вероятно, означает __den это ноль. Это значение берется из подсчета сегментов хэш-карты, которое не должно быть равным нулю.

Можете ли вы подтвердить это, когда он падает m._M_bucket_count это ноль?

Если так, то это либо указывает на то, что вы как-то испортили карту (пробовали ли вы с -D_GLIBCXX_DEBUG включить проверки режима отладки libstdc ++? Вы пытались бежать под valgrind?) или есть ошибка в коде libstdc ++.

6

Другие решения

У меня была точно такая же проблема. Это было вызвано тем, что memset случайно был применен к данным контейнера.

4

В моем случае такая же проблема возникла из-за статического фиаско init.
Из одного объектного файла я вызвал метод emplace для статического std :: unordered_map, который был определен во втором объектном файле. Из-за того, что в начале данные были в BSS, значение счетчика сегментов было равно нулю => SIGFPE.

2
По вопросам рекламы [email protected]