Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

destruction of move-constructed map using private_adaptive_pool triggers Assertion `n_free_nodes == m_totally_free_blocks' failed. #247

Open
aleden opened this issue Jan 2, 2025 · 2 comments

Comments

@aleden
Copy link

aleden commented Jan 2, 2025

Minimal reproducible example here: https://gcc.godbolt.org/z/KGefcocv6

#include <boost/interprocess/allocators/private_adaptive_pool.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/managed_heap_memory.hpp>
#include <cstdint>

typedef boost::interprocess::managed_heap_memory::segment_manager
    segment_manager_t;

typedef boost::interprocess::map<
    uint32_t, uint32_t, std::less<uint32_t>,
    boost::interprocess::private_adaptive_pool<
        std::pair<const uint32_t, uint32_t>, segment_manager_t>>
    mymap_t;

int main() {
  boost::interprocess::managed_heap_memory heap_mem(1u << 20);

  {
    mymap_t bbmap(heap_mem.get_segment_manager());

    bbmap.emplace(1, 2);

    mymap_t bbmap2(boost::move(bbmap));
  } // <= CRASHES HERE

  return 0;
}
$ g++ -o test test.cpp && ./test
test: /usr/include/boost/container/detail/adaptive_node_pool_impl.hpp:932: void boost::container::dtl::private_adaptive_node_pool_impl_common<SegmentManagerBase, Flags>::priv_clear(size_type, size_type, size_type) [with SegmentManagerBase = boost::interprocess::segment_manager_base<boost::interprocess::rbtree_best_fit<boost::interprocess::null_mutex_family> >; unsigned int Flags = 6; size_type = long unsigned int]: Assertion `n_free_nodes == m_totally_free_blocks' failed.
Aborted (core dumped)
@aleden aleden changed the title move constructing map that uses private_adaptive_pool triggers Assertion `n_free_nodes == m_totally_free_blocks' failed. destruction of move-constructed map using private_adaptive_pool triggers Assertion `n_free_nodes == m_totally_free_blocks' failed. Jan 2, 2025
@aleden
Copy link
Author

aleden commented Jan 2, 2025

This bug is also present with private_node_allocator.

#include <boost/interprocess/allocators/private_node_allocator.hpp>                                                                                                                                                                 
#include <boost/interprocess/containers/map.hpp>                                 
#include <boost/interprocess/managed_heap_memory.hpp>                            
#include <cstdint>                                                               
                                                                                 
typedef boost::interprocess::managed_heap_memory::segment_manager                
    segment_manager_t;                                                           
                                                                                 
typedef boost::interprocess::map<                                                
    uint32_t, uint32_t, std::less<uint32_t>,                                     
    boost::interprocess::private_node_allocator<                                 
        std::pair<const uint32_t, uint32_t>, segment_manager_t>>                 
    mymap_t;                                                                     
                                                                                 
int main() {                                                                     
  boost::interprocess::managed_heap_memory heap_mem(1u << 20);                   
                                                                                 
  {                                                                              
    mymap_t bbmap(heap_mem.get_segment_manager());                               
                                                                                 
    bbmap.emplace(1, 2);                                                         
                                                                                 
    { mymap_t bbmap2(boost::move(bbmap)); }                                      
  }                                                                              
                                                                                 
  return 0;                                                                      
}                                                                                

I'm suspecting that something is wrong with interprocess::map, since interprocess::flat_map seems to be fine with these examples.

@aleden
Copy link
Author

aleden commented Jan 2, 2025

I just confirmed that if the same allocator instance is used, there is no assertion triggered. i.e.

#include <boost/interprocess/allocators/private_adaptive_pool.hpp>               
#include <boost/interprocess/containers/map.hpp>                                 
#include <boost/interprocess/managed_heap_memory.hpp>                            
#include <cstdint>                                                               
                                                                                 
typedef boost::interprocess::managed_heap_memory::segment_manager                
    segment_manager_t;                                                           
                                                                                 
typedef boost::interprocess::map<                                                
    uint32_t, uint32_t, std::less<uint32_t>,                                     
    boost::interprocess::private_adaptive_pool<                                  
        std::pair<const uint32_t, uint32_t>, segment_manager_t>>                 
    mymap_t;                                                                     
                                                                                 
int main() {                                                                     
  boost::interprocess::managed_heap_memory heap_mem(1u << 20);                   
                                                                                 
  boost::interprocess::private_adaptive_pool<std::pair<const uint32_t, uint32_t>, segment_manager_t> A(heap_mem.get_segment_manager());
                                                                                 
  {                                                                              
    mymap_t bbmap(A);                                                            
                                                                                 
    bbmap.emplace(1, 2);                                                         
                                                                                                                                                                                                                                    
    { mymap_t bbmap2(A);                                                         
      bbmap2 = boost::move(bbmap); }                                             
  }                                                                              
                                                                                 
  return 0;                                                                      
}                                                                                

Works.

Moving one container into another container that does not share exactly the same allocator instance triggers a deep-copy‐and‐reinsert of all elements. So I'm guessing there's a bug in the deep-copy somewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant