I'm trying to transfer a std::vector<std::string>
to a newly forked process via Boost.Interprocess, so that the child process takes ownership of it and destroy it. Retrieving and reading the vector works, however I'm getting an access violation upon destroying it. I gather that the allocator embarks some state with pointers which point into the parent's address space and are meaningless in the child's one.
How am I supposed to create that vector in the parent and destroy in the child correctly ?
Parent process code:
namespace ip = boost::interprocess;
template <class T>
using ip_allocator = ip::allocator<T, ip::managed_shared_memory::segment_manager>;
template <class T>
using ip_vector = std::vector<T, ip_allocator<T>>;
int CALLBACK WinMain(
_In_ HINSTANCE,
_In_ HINSTANCE,
_In_ LPSTR,
_In_ int
) {
ip::shared_memory_object::remove("MyTestShm");
ip::managed_shared_memory mshm{ ip::open_or_create, "MyTestShm", 1024 * 1024 };
ip_allocator<int> intAlloc{ mshm.get_segment_manager() };
mshm.construct<ip_vector<int>>("ForkData")(
ip_vector<int>{ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, intAlloc}
);
boost::process::spawn(L"Executor.exe", L"ForkData");
}
Child process (Executor.exe
) code:
int wmain(int argc, wchar_t **argv) try {
namespace ip = boost::interprocess;
// Kludge to attach the debugger and force continuation
bool volatile coin = true;
while (coin)
::Sleep(1000);
ip::managed_shared_memory mshm{ ip::open_only, "MyTestShm" };
auto const * const fd = mshm.find<ip_vector<int>>("ForkData").first;
if(!fd)
return 1;
for (int i : *fd)
std::cout << i << ' ';
std::cout << '\n';
mshm.destroy_ptr(fd); // Crashing line
}
catch (std::exception const &exc) {
std::cerr
<< "Unhandled " << boost::typeindex::type_id_runtime(exc).pretty_name() << ":\n"
<< exc.what() << '\n';
return 1;
}
Error and callstack:
Exception thrown: read access violation.
_Pnext
was0x21FE21200B0
. occurred
Executor.exe!std::_Container_base12::_Orphan_all() Line 221
Executor.exe!std::_Vector_alloc<std::_Vec_base_types<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > >::_Orphan_all() Line 536
Executor.exe!std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > >::_Tidy() Line 1913
Executor.exe!std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > >::~vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > >() Line 894
Executor.exe!std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > >::`scalar deleting destructor'(unsigned int) Executor.exe!boost::interprocess::ipcdetail::placement_destroy<std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > >::destroy_n(void * mem, unsigned __int64 num, unsigned __int64 & destroyed) Line 61
Executor.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::priv_generic_named_destroy<char>(const char * name, boost::interprocess::iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0> > > & index, boost::interprocess::ipcdetail::in_place_interface & table, boost::interprocess::ipcdetail::bool_<1> is_intrusive_index) Line 976
Executor.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::priv_generic_named_destroy<char>(boost::interprocess::ipcdetail::block_header<unsigned __int64> * block_header, boost::interprocess::iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0> > > & index, boost::interprocess::ipcdetail::in_place_interface & table, boost::interprocess::ipcdetail::bool_<0> is_node_index) Line 929
Executor.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::priv_destroy_ptr(const void * ptr, boost::interprocess::ipcdetail::in_place_interface & dtor) Line 777
Executor.exe!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::destroy_ptr<std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > >(const std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > * p) Line 550
Executor.exe!boost::interprocess::ipcdetail::basic_managed_memory_impl<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index,8>::destroy_ptr<std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > >(const std::vector<int,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index> > > * ptr) Line 608
Executor.exe!wmain(int argc, wchar_t * * argv) Line 31
Executor.exe!invoke_main() Line 91
Executor.exe!__scrt_common_main_seh() Line 288
Executor.exe!__scrt_common_main() Line 331
Executor.exe!wmainCRTStartup() Line 17
kernel32.dll!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()