簡體   English   中英

SEGV在gcc的std :: unordered_map中

[英]SEGV in gcc's std::unordered_map

我在gcc 4.7.2的unordered_map遇到了SEGV

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為空; _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;
    }

我不是100%了解unordered_map的內部工作原理-是否要求存儲桶_M_nxt中的第一個節點不為空,或者這是一個錯誤?

這個問題顯然是針對GCC的實現,但是我很確定,如果_M_buckets[__n]不為空,那么_M_buckets[__n]->_M_nxt也應為非空。

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

嘗試使用-D_GLIBCXX_DEBUG ,看看它是否可以識別代碼問題,這可能是一個錯誤,但是您更有可能損壞了容器或使用了錯誤的容器。

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

#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

原因很簡單,並發訪問解決方案是同步。

我希望這會幫助某人;)

除非您在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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM