martinus / robin-hood-hashing

Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20
https://gitter.im/martinus/robin-hood-hashing
MIT License
1.52k stars 146 forks source link

Segmentation fault after copy assignment #23

Closed TheLartians closed 5 years ago

TheLartians commented 5 years ago

Hello, thank you for your great Library! While testing, I found that the following code resulted in a segmentation fault.

#include <robin_hood.h>
#include <string>

int main(){
  robin_hood::unordered_map<std::string,std::string> map;
  robin_hood::unordered_map<std::string,std::string> tmp;
  map.emplace("a", "b");
  map = tmp;
  map.emplace("c", "d");
  return 0;
}

I tried version 3.2.7 and the current master under MacOs 10.14.4 using clang and g++8.

edit: simplify example

TheLartians commented 5 years ago

Stack traceback for completeness.

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7)
    frame #0: 0x0000000100001b61 Test`robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::nextWhileLess(this=0x00007ffeefbff888, info=0x00007ffeefbff724, idx=0x00007ffeefbff728) const at robin_hood.h:1049:24
   1046
   1047     void nextWhileLess(InfoType* info, size_t* idx) const {
   1048         // unrolling this by hand did not bring any speedups.
-> 1049         while (*info < mInfo[*idx]) {
   1050             next(info, idx);
   1051         }
   1052     }
Target 0: (Test) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7)
  * frame #0: 0x0000000100001b61 Test`robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::nextWhileLess(this=0x00007ffeefbff888, info=0x00007ffeefbff724, idx=0x00007ffeefbff728) const at robin_hood.h:1049:24
    frame #1: 0x0000000100001573 Test`std::__1::pair<robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::Iter<false>, bool> robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::doInsert<robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::DataNode<robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, true> >(this=0x00007ffeefbff888, keyval=0x00007ffeefbff788) at robin_hood.h:1729:13
    frame #2: 0x0000000100001057 Test`std::__1::pair<robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::Iter<false>, bool> robin_hood::detail::unordered_map<true, 80ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, robin_hood::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::emplace<char const (this=0x00007ffeefbff888, args=<no value available>, args=<no value available>) [2], char const (&) [2]>(char const (&) [2], char const (&) [2]) at robin_hood.h:1419:18
    frame #3: 0x0000000100000f2c Test`main at test.cpp:10:7
    frame #4: 0x00007fff7b1593d5 libdyld.dylib`start + 1
naav commented 5 years ago

I believe line 1294 should instead be:

mInfo = reinterpret_cast<uint8_t*>(&mMask);
martinus commented 5 years ago

Thank you a lot for finding this! I need more test coverage :( It's fixed now

TheLartians commented 5 years ago

Awesome, thanks for fixing this!