id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 9601,Unable to load archives with pointer instances which contain self reference cycles in 1.55,Brandon Kohn,Robert Ramey,"First the original pointer is loaded like so: {{{ #!c++ // because the following operation could move the items // don't use co after this // add to list of serialized objects so that we can properly handle // cyclic strucures //! Note: t's value is undefined at this point. It's whatever value it had when serialization was called. object_id_vector.push_back(aobject(t, cid)); // remember that that the address of these elements could change // when we make another call so don't use the address bpis_ptr->load_object_ptr( ar, t, m_pending.version ); BOOST_ASSERT(NULL != t); //! Note: The object_id_vector element's address is not updated until the load is complete. [1] object_id_vector[ui].address = t; }}} load_object_ptr will eventually lead to: {{{ #!c++ template BOOST_DLLEXPORT void pointer_iserializer::load_object_ptr( basic_iarchive & ar, void * & x, const unsigned int file_version ) const { ... //! This serializes an instance of T ar_impl >> boost::serialization::make_nvp(NULL, * t); } }}} If t contains a cyclic reference to itself then the following is called: {{{ #!c++ // extra line to evade borland issue const bool tracking = co.tracking_level; // if we're tracking and the pointer has already been read if(tracking && ! track(ar, t)) // we're done return bpis_ptr; }}} track will check if the oid is already loaded and assign the address of the previously loaded pointer. {{{ #!c++ bool basic_iarchive_impl::track( basic_iarchive & ar, void * & t ){ ... // if its a reference to a old object if(object_id_type(object_id_vector.size()) > oid){ // we're done //! Note this line: *** [2] t = object_id_vector[oid].address; return false; } return true; } }}} Recall back at the original scope [1]: remember that that the address of these elements could change {{{ #!c++ // when we make another call so don't use the address bpis_ptr->load_object_ptr( ar, t, m_pending.version ); BOOST_ASSERT(NULL != t); //! The assignment to object_id_vector[ui].address takes place after the cycle is loaded. //! This means means the value assigned to t at [2] is undefined. object_id_vector[ui].address = t; }}} Here's a unit test that illustrates the issue: {{{ #!c++ namespace TestPointerSerializationReferenceCycle { struct PointerHolder { PointerHolder(PointerHolder* ptr = nullptr) : Ptr(ptr) {} PointerHolder* Ptr; template void serialize(Archive& ar, const unsigned int v) { ar & Ptr; } }; } BOOST_AUTO_TEST_CASE(TestPointerReferenceCycleLoad) { using namespace TestPointerSerializationReferenceCycle; std::stringstream buff(std::stringstream::in | std::stringstream::out); //! Write it. { PointerHolder* pPtrHldr = new PointerHolder(); pPtrHldr->Ptr = pPtrHldr; boost::archive::text_oarchive ar(buff); ar & pPtrHldr; } //! Read it. { buff.seekg(0); PointerHolder* pPtrHldr = reinterpret_cast(0xBAADF00D); boost::archive::text_iarchive ar(buff); ar & pPtrHldr; BOOST_CHECK(pPtrHldr != nullptr); if (pPtrHldr != nullptr) { BOOST_CHECK(pPtrHldr->Ptr == pPtrHldr);//! At this point pPtrHldr->Ptr == 0xBAADFOOD. } } } }}} ",Bugs,closed,To Be Determined,serialization,Boost 1.55.0,Problem,fixed,,