pool allocator with Microsoft STL’s std::map

  allocator, c++, stl, visual-c++

I’m trying to use this allocator with std::map on VS2017, however it is failing debug mode asserts so there seems to be something wrong. Here’s a minimal sample of the code after trimming it down.

#include "plalloc.hpp"
#include <map>

typedef unsigned char uchar;

struct my_info_t
{
  int src, dst;
  char type;
  bool operator <(const my_info_t &r) const
  {
    if ( src < r.src )
      return true;
    if ( src > r.src )
      return false;
    return dst < r.dst;
  }
};

typedef plalloc<std::pair<const my_info_t, uchar> > xcache_alloc;
typedef std::map<my_info_t, uchar, std::less<my_info_t>, xcache_alloc> my_cache_t;


int main()
{
 my_cache_t xc;
 my_info_t xi = {1, 2, 3};
 xc[xi] =42;
}

In the original code it was breaking on this line in <xtree>:

 #if _ITERATOR_DEBUG_LEVEL == 2
        _STL_VERIFY(_Where._Getcont() == _STD addressof(_My_data), "map/set insert iterator outside range");
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

However, with the stripped-down sample I’m getting a deleted pointer access in _Iterator_base12::_Adopt():

    void _Adopt(const _Container_base12 *_Parent) noexcept
        {   // adopt this iterator by parent
        if (_Parent == nullptr)
            {   // no future parent, just disown current parent
 #if _ITERATOR_DEBUG_LEVEL == 2
            _Lockit _Lock(_LOCK_DEBUG);
            _Orphan_me();
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
            }
        else
            {   // have a parent, do adoption
            _Container_proxy *_Parent_proxy = _Parent->_Myproxy; // <== **** CRASH HERE

The _Parent has value 0xdddddddd, so it’s been deleted. Here’s the full stack trace:

>   Project1.exe!std::_Iterator_base12::_Adopt(const std::_Container_base12 * _Parent=0xdddddddd) Line 157  C++
    Project1.exe!std::_Iterator_base12::operator=(const std::_Iterator_base12 & _Right={...}) Line 135  C++
    Project1.exe!std::_Iterator_base12::_Iterator_base12(const std::_Iterator_base12 & _Right={...}) Line 116   C++
    Project1.exe!std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > >,std::_Iterator_base12>::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > >,std::_Iterator_base12>(const std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > >,std::_Iterator_base12> & __that={...})  C++
    Project1.exe!std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > > >::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > > >(const std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<my_info_t const ,unsigned char> > > > & __that={...})   C++
    Project1.exe!std::map<my_info_t,unsigned char,std::less<my_info_t>,plalloc<std::pair<my_info_t const ,unsigned char> > >::_Try_emplace<my_info_t const &>(const my_info_t & _Keyval={...}) Line 232 C++
    Project1.exe!std::map<my_info_t,unsigned char,std::less<my_info_t>,plalloc<std::pair<my_info_t const ,unsigned char> > >::try_emplace<>(const my_info_t & _Keyval={...}) Line 248   C++
    Project1.exe!std::map<my_info_t,unsigned char,std::less<my_info_t>,plalloc<std::pair<my_info_t const ,unsigned char> > >::operator[](const my_info_t & _Keyval={...}) Line 363  C++
    Project1.exe!main() Line 29 C++

Unfortunately, the Dinkumware-originating code is pretty obscure (especially the proxy allocator thingy – what’s that?) so it’s difficult to figure out what is going on. Is the problem in the allocator, my use of it, or Microsoft’s STL?

Source: Windows Questions C++

LEAVE A COMMENT