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