2013-05-03 50 views
2

我在GCC遇到SEGV 4.7.2的unordered_mapSEGV在海合會的std :: unordered_map

find()它調用_M_find_node,進而調用_M_find_before_node,傳遞桶數目,則關鍵我們重新搜索,以及哈希碼

_M_find_before_node,它查找第一個節點在桶中的問題:

_BaseNode* __prev_p = _M_buckets[__n]; 

,然後得到以下這個節點:

_Node* __p = static_cast<_Node*>(__prev_p->_M_nxt); 

的問題是,__prev_p->_M_nxt爲null; _M_equals試圖解引用它並導致seg錯誤。

我不是100%在unordered_map的內部工作線索 - 是否要求桶中的第一個節點的_M_nxt是非空的,或者這是一個錯誤?

有問題的代碼是在這裏:

// Find the node whose key compares equal to k in the bucket n. Return nullptr 
    // if no node is found. 
    template<typename _Key, typename _Value, 
     typename _Allocator, typename _ExtractKey, typename _Equal, 
     typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 
     bool __chc, bool __cit, bool __uk> 
    typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, 
      _Equal, _H1, _H2, _Hash, _RehashPolicy, 
      __chc, __cit, __uk>::_BaseNode* 
    _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, 
      _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: 
    _M_find_before_node(size_type __n, const key_type& __k, 
      typename _Hashtable::_Hash_code_type __code) const 
    { 
     _BaseNode* __prev_p = _M_buckets[__n]; 
     if (!__prev_p) 
    return nullptr; 
     _Node* __p = static_cast<_Node*>(__prev_p->_M_nxt); // __p is null here!! 
     for (;; __p = __p->_M_next()) 
    { 
     if (this->_M_equals(__k, __code, __p)) 
     return __prev_p; 
     if (!(__p->_M_nxt) || _M_bucket_index(__p->_M_next()) != __n) 
     break; 
     __prev_p = __p; 
    } 
     return nullptr; 
    } 
+3

爲什麼你不顯示觸發這個錯誤的代碼?如果代碼是正確的,你應該提交一個錯誤報告。如果沒有,你會解決你的問題:) – Mat 2013-05-03 07:03:37

+3

個人而言,我會首先在我自己的代碼中尋找錯誤。你有自己的代碼片段重現了這個bug嗎? – john 2013-05-03 07:03:58

+0

無法在一個簡單的示例中重現 - 正試圖! :/ – 2013-05-03 07:06:33

回答

1
更換

我不是100%在unordered_map的內部工作線索 - 是否需要一個桶的第一個節點_M_nxt非空,或者這是一個錯誤?

的問題顯然是專門針對GCC的實現,但我敢肯定,如果_M_buckets[__n]非null,則_M_buckets[__n]->_M_nxt應該是非空了。

即,如果存儲桶爲空,則爲_M_buckets[__n]==nullptr,如果存儲桶不空,則_M_buckets[__n]->_M_nxt是存儲桶中的第一個節點。

嘗試使用-D_GLIBCXX_DEBUG進行構建,看看它是否可以識別您的代碼存在問題,但可能存在一個錯誤,但它更可能以某種方式損壞了容器或者錯誤地使用了它。

1

除非你已經檢測到GCC std::unorderd_map執行一個錯誤,你的錯誤的最可能的原因是你不喜歡的東西:

std::unorderd_map<MyKey, MyValue> my_map; 
auto it = my_map.find(some_key); // if some_key was not found, it == my_map.end() 
do something with *it;   // kaboom! derefence of past-the-end iterator 

如果是這樣的情況下,

if (it != my_map.end()) { 
    do something with *it; 
} 
1

問題現在已經很老了,但我最近也遇到過同樣的問題,下面是如何重現它的示例代碼。

#include <chrono> 
#include <iostream> 
#include <thread> 
#include <unordered_map> 

int main() 
{ 
    std::unordered_map< std::string, int > m_Map{}; 

    m_Map.insert(std::make_pair("a", 0x61)); 
    auto count{1000u}; 

    auto t_remove = std::thread([&m_Map, &count]() { 

     while (1) 
     { 
     m_Map.erase("a"); 
     std::this_thread::sleep_for(std::chrono::nanoseconds(count)); 
     if(count > 10) 
     { 
      count-=10; 
     } 
     else 
     { 
      count = 1000u; 
     } 
     m_Map.insert(std::make_pair("a", 0x61)); 
     } 
    }); 

    while (1) 
    { 
     auto it = m_Map.find("a"); 

     if (it != m_Map.end()) 
     { 
     std::cerr << "Map has a " << it->first << " = " << it->second << "\n"; 
     } 
     else 
     { 
     std::cerr << "Map does not have a \"a\"\n"; 
     } 
    } 

    t_remove.join(); 
    return 0; 
} 

在幾次迭代(GDB)之後的結果:

Thread 1 "find_stress_tes" received signal SIGSEGV, Segmentation fault. 
0x000000000040505b in std::__detail::_Equal_helper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, unsigned long, true>::_S_equals (__eq=..., __extract=..., __k="a", __c=4993892634952068459, __n=0x0) 
    at /usr/include/c++/5/bits/hashtable_policy.h:1322 
1322  { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v())); } 
(gdb) bt 
#0 0x000000000040505b in std::__detail::_Equal_helper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, unsigned long, true>::_S_equals (__eq=..., __extract=..., __k="a", __c=4993892634952068459, __n=0x0) 
    at /usr/include/c++/5/bits/hashtable_policy.h:1322 
#1 0x0000000000404b2a in std::__detail::_Hashtable_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Hashtable_traits<true, false, true> >::_M_equals (this=0x7fffffffdd40, __k="a", 
    __c=4993892634952068459, __n=0x0) at /usr/include/c++/5/bits/hashtable_policy.h:1704 
#2 0x00000000004044ef in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::_M_find_before_node (this=0x7fffffffdd40, __n=1, 
    __k="a", __code=4993892634952068459) at /usr/include/c++/5/bits/hashtable.h:1433 
#3 0x0000000000403e50 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::_M_find_node (this=0x7fffffffdd40, __bkt=1, __key="a", 
    __c=4993892634952068459) at /usr/include/c++/5/bits/hashtable.h:632 
#4 0x000000000040392b in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::find (this=0x7fffffffdd40, __k="a") 
    at /usr/include/c++/5/bits/hashtable.h:1307 
#5 0x0000000000403675 in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::find (this=0x7fffffffdd40, 
    __x="a") at /usr/include/c++/5/bits/unordered_map.h:615 
#6 0x000000000040184b in main() at ../find_stress_test/main.cpp:40 

原因說起來很簡單,併發訪問,解決方案將是同步的。

我希望能幫到別人;)

+0

這非常整齊,確實應該標記爲正確的答案。 – 2018-02-09 15:24:20