mercredi 26 juin 2019

List destructor causing crash in thread-local singleton class

I've tried to create thread-local singleton class with member of std::list type. During testing my solution with multiple threads, I've encountered strange crash caused by std::list destructor (more precisely, _M_clear() method invoked by destructor). It happens even without performing any operations on mentioned list. What is even more strange - this crash ocurrs randomly.

Any ideas, what can be problem here?

Below is minimal example to repreduce this error:

#include <list>
#include <thread>

class tls_list_test
{
private:
    std::list<int> test_list;

    tls_list_test() = default;

    ~tls_list_test() = default;

public:
    static tls_list_test& get_instance()
    {
        thread_local tls_list_test instance;
        return instance;
    }
};

int main()
{
    std::list<std::thread> threads;

    for (int i = 0; i < 3; ++i)
    {
        std::thread thread([]()
           {
               auto& instance = tls_list_test::get_instance();
           });
        threads.push_back(std::move(thread));
    }

    for (auto& thread : threads)
    {
        thread.join();
    }

    return 0;
}

Code in std::list causing segfault:

  template<typename _Tp, typename _Alloc>
    void
    _List_base<_Tp, _Alloc>::
    _M_clear() _GLIBCXX_NOEXCEPT
    {
      typedef _List_node<_Tp>  _Node;
      __detail::_List_node_base* __cur = _M_impl._M_node._M_next;
      while (__cur != &_M_impl._M_node)
    {
      _Node* __tmp = static_cast<_Node*>(__cur);
      __cur = __tmp->_M_next; // <- SEGFAULT on this line
      _Tp* __val = __tmp->_M_valptr();
#if __cplusplus >= 201103L
      _Node_alloc_traits::destroy(_M_get_Node_allocator(), __val);
#else
      _Tp_alloc_type(_M_get_Node_allocator()).destroy(__val);
#endif
      _M_put_node(__tmp);
    }
    }

GDB Variables:

Signal = SIGSEGV (Segmentation fault)
__tmp = {std::__cxx11::_List_base<int, std::allocator>::_Node * | 0xfeeefeeefeeefeee} 0xfeeefeeefeeefeee
__val = {int * | 0x2ee4448} 0x2ee4448
this = {std::__cxx11::_List_base<int, std::allocator> * const | 0x2ee5be8} 0x2ee5be8
__cur = {std::__detail::_List_node_base * | 0xfeeefeeefeeefeee} 0xfeeefeeefeeefeee

G++ version:

g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0

Aucun commentaire:

Enregistrer un commentaire