Boost C++ Libraries: Ticket #2217: serialization 1.36.0 extended_type_info exit issue(s) https://svn.boost.org/trac10/ticket/2217 <p> I'm running some serialization unit-tests which pass with flying colors under 1.35.0 and earlier, however they seg-fault on exit when run through 1.36.0. </p> <blockquote> <p> The error appears to deal with destruction of extended_type_info_typeid objects, and *only* manifests itself when I load an archive through a shared_ptr&lt;T&gt;. The load will appear to function properly, then on exit of the application, &lt;&lt;Death&gt;&gt;. This occurs even if I remove BOOST_CLASS_EXPORT &amp;&amp; BOOST_CLASS_TYPE_INFO as the shared_ptr is to the derived element, and I'm not testing through a base. </p> </blockquote> <p> <em></em><em></em><em></em><em></em><em></em><em></em><em></em> snippet: <em></em><em></em><em></em><em></em><em></em><em></em><em></em> BOOST_AUTO_TEST_CASE( MyTestClass_Serialization ) { </p> <blockquote> <p> <em> <a class="missing wiki">MyTestClass</a> is an uses intrusive serialization (You could use any object) </em></p> </blockquote> <blockquote> <p> boost::shared_ptr&lt;<a class="missing wiki">MyTestClass</a>&gt; outtie ( new <a class="missing wiki">MyTestClass</a>() ); boost::shared_ptr&lt;<a class="missing wiki">MyTestClass</a>&gt; innie; </p> </blockquote> <p> </p> <blockquote> <p> std::ofstream os( "MyTestClass_Serialization.xml", std::ios_base::out ); boost::archive::xml_oarchive xmlao(os); xmlao &lt;&lt; boost::serialization::make_nvp( "testKey", outtie ); os.close(); </p> </blockquote> <blockquote> <p> std::ifstream is( "MyTestClass_Serialization.xml", std::ios_base::in ); boost::archive::xml_iarchive xmlai( is ); xmlai &gt;&gt;boost::serialization::make_nvp( "testKey", innie ); is.close(); </p> </blockquote> <p> </p> <blockquote> <p> BOOST_CHECK_NO_THROW(); </p> </blockquote> <p> } </p> <p> Ran on Ubuntu(Linux) 8.04 using gcc 4.2.3 <em></em><em></em><em></em><em></em><em></em><em></em><em></em> gdb output: <em></em><em></em><em></em><em></em><em></em><em></em><em></em> <strong>* No errors detected [New Thread 0xb73e26c0 (LWP 4715)] </strong></p> <p> Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb73e26c0 (LWP 4715)] 0xb76bb56b in std::_Rb_tree_rebalance_for_erase () from /usr/lib/libstdc++.so.6 (gdb) bt <a class="missing ticket">#0</a> 0xb76bb56b in std::_Rb_tree_rebalance_for_erase () from /usr/lib/libstdc++.so.6 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/1" title="#1: Bugs: boost.build causes ftjam to segfault (closed: Wont Fix)">#1</a> 0xb7a38221 in std::_Rb_tree&lt;boost::serialization::detail::extended_type_info_typeid_0 const*, boost::serialization::detail::extended_type_info_typeid_0 const*, std::_Identity&lt;boost::serialization::detail::extended_type_info_typeid_0 const*&gt;, boost::serialization::detail::type_compare, std::allocator&lt;boost::serialization::detail::extended_type_info_typeid_0 const*&gt; &gt;::erase (this=0xb7a93c94, <span class="underline">position={_M_node = 0x810a3f8}) at /usr/include/c++/4.2/bits/stl_tree.h:1261 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/2" title="#2: Bugs: list::size should be const (closed: fixed)">#2</a> 0xb7a38270 in std::multiset&lt;boost::serialization::detail::extended_type_info_typeid_0 const*, boost::serialization::detail::type_compare, std::allocator&lt;boost::serialization::detail::extended_type_info_typeid_0 const*&gt; &gt;::erase (this=0xb7a93c94, </span>position={_M_node = 0x810a3f8}) at /usr/include/c++/4.2/bits/stl_multiset.h:346 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3" title="#3: Bugs: automatic conversion and overload proble (closed: fixed)">#3</a> 0xb7a37482 in boost::serialization::detail::extended_type_info_typeid_0::type_unregister (this=0x810749c) at /opt/tomodev/env/boost/libs/serialization/src/extended_type_info_typeid.cpp:93 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4" title="#4: Bugs: any_ptr in any library documentation? (closed: Fixed)">#4</a> 0x080b001a in ~extended_type_info_typeid (this=0x810749c) at /opt/tomodev/env/boost/boost/serialization/extended_type_info_typeid.hpp:80 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/5" title="#5: Bugs: shared_ptr and self-owning objects (closed: Fixed)">#5</a> 0x0809ebe2 in <span class="underline">tcf_49 () at /opt/tomodev/env/boost/boost/serialization/singleton.hpp:104 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/6" title="#6: Bugs: tie in utility.hpp and tuple.hpp clash. (closed: Duplicate)">#6</a> 0xb74f7084 in exit () from /lib/tls/i686/cmov/libc.so.6 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7" title="#7: Bugs: g++ 2.96 requires NO_STRINGSTREAM (closed: Fixed)">#7</a> 0xb74df458 in </span>libc_start_main () from /lib/tls/i686/cmov/libc.so.6 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8" title="#8: Bugs: prop in undirected graph + out_edges (closed: Works For Me)">#8</a> 0x0809e691 in _start () </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/2217 Trac 1.4.3 benjamin.sternlieb@… Tue, 19 Aug 2008 16:15:13 GMT <link>https://svn.boost.org/trac10/ticket/2217#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:1</guid> <description> <p> We also have the same issue. SEGV associated with </p> <p> <a class="missing ticket">#0</a> std::_Rb_tree_rebalance_for_erase (<span class="underline">z=0x93834c8, </span>header=@0x71fa08) at ../../.././libstdc++-v3/src/tree.cc:337 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/1" title="#1: Bugs: boost.build causes ftjam to segfault (closed: Wont Fix)">#1</a> 0x006ec048 in boost::serialization::detail::extended_type_info_typeid_0::type_unregister () </p> <blockquote> <p> from /sbcimp/dyn/data/superqa/ultrabond/third_party/4.1.2/boost_1_36/lib/libboost_serialization-gcc41-mt-1_36.so.1.36.0 </p> </blockquote> <p> <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/2" title="#2: Bugs: list::size should be const (closed: fixed)">#2</a> 0x0828d66e in ~extended_type_info_typeid (this=0x84490c0) </p> <blockquote> <p> at /sbcimp/dyn/data/superqa/ultrabond/third_party/4.1.2/boost_1_36/include/boost-1_36/boost/serialization/extended_type_info_typeid.hpp:80 </p> </blockquote> <p> We're rolling back to 1.34.1 </p> </description> <category>Ticket</category> </item> <item> <author>Ryan Mulder <rjmyst3@…></author> <pubDate>Wed, 27 Aug 2008 17:36:26 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2217#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:2</guid> <description> <p> With MinGW 4.2.1-dw2, in a debug build, there is an assertion failure at close: </p> <p> File: libs\serialization\src\extended_type_info.cpp Line: 47 </p> <p> Expression: NULL != l </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Brandon Kohn</dc:creator> <pubDate>Thu, 28 Aug 2008 22:30:09 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2217#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:3</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2217#comment:2" title="Comment 2">Ryan Mulder &lt;rjmyst3@gmail.com&gt;</a>: </p> <blockquote class="citation"> <p> With MinGW 4.2.1-dw2, in a debug build, there is an assertion failure at close: </p> <p> File: libs\serialization\src\extended_type_info.cpp Line: 47 </p> <p> Expression: NULL != l </p> </blockquote> <p> I think I have found and fixed an issue with the type_unregister and key_unregister functions. The problem seems to be with the removal of items from the multiset containing them. The items are inserted into the multiset via ptr and sorted on fields m_key or m_ti respectively. When the items are deleted from the multiset, a lower/upper bound search is performed to find the range of keys which contain the specified value (m_key, m_ti) and then subsequently the iterators on that range are subject to: </p> <blockquote> <p> detail::ktmap::iterator start = x.lower_bound(this); detail::ktmap::iterator end = x.upper_bound(this); assert(start != end); </p> </blockquote> <blockquote> <p> <em> remove entry in map which corresponds to this type do{ </em></p> <blockquote> <p> if(this == *start){ </p> <blockquote> <p> x.erase(start); break; </p> </blockquote> <p> } </p> </blockquote> <p> }while(++start != end); </p> </blockquote> <blockquote> <p> m_key = NULL; </p> </blockquote> <p> Note that it breaks after removing the first item. It then sets the key to NULL. This means that on subsequent compares inside the set, if there are other instances of this key (which are held via ptr), the value of m_key is NULL. Inside the key_compare there are assert statements to check that m_key isn't NULL... after that all hell breaks lose :D. </p> <p> The same pattern is in extended_type_info_typeid.cpp. I fixed my local copy by changing the loop to use: </p> <blockquote> <p> do{ </p> <blockquote> <p> if(this == *start){ </p> <blockquote> <p> start = x.erase(start); </p> </blockquote> <p> } else { </p> <blockquote> <p> ++start; </p> </blockquote> <p> } </p> </blockquote> <p> }while(start != end); </p> </blockquote> <p> So all copies of an item with the same m_key or m_ti value are removed. After that everything seemed to run fine. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Brandon Kohn</dc:creator> <pubDate>Thu, 28 Aug 2008 22:32:05 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/2217 https://svn.boost.org/trac10/ticket/2217 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">extended_type_info_files.patch</span> </li> </ul> <p> Patches for extended_type_info_typeid.cpp and extended_type_info.cpp </p> Ticket Ryan Mulder <rjmyst3@…> Fri, 29 Aug 2008 15:00:35 GMT <link>https://svn.boost.org/trac10/ticket/2217#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:4</guid> <description> <p> Slight bug in your patch which prevents it from compiling with MinGW 4.2.1: multiset::erase returns void. </p> <p> changing </p> <pre class="wiki">start = x.erase(start); </pre><p> to </p> <pre class="wiki">x.erase(start++); </pre><p> fixes it. </p> </description> <category>Ticket</category> </item> <item> <author>Ryan Mulder <rjmyst3@…></author> <pubDate>Fri, 29 Aug 2008 15:06:56 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/2217 https://svn.boost.org/trac10/ticket/2217 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">extended_type_info_files2.patch</span> </li> </ul> Ticket matthew.downey@… Thu, 04 Sep 2008 23:08:37 GMT <link>https://svn.boost.org/trac10/ticket/2217#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:5</guid> <description> <p> I am getting a similar problem: a SIGSEGV is thrown on exit. The supplied patch did not fix the problem. </p> <p> MSVC8 call stack: </p> <pre class="wiki">msvcr80d.dll!_free_base(void * pBlock=0x007938e0) Line 109 + 0x13 bytes C commonTest.exe!boost::detail::allocator_impl&lt;20,4&gt;::dealloc(void * pv=0x002c8870) Line 149 C++ commonTest.exe!boost::detail::sp_counted_impl_pd&lt;boost::thread_specific_ptr&lt;Common::ThreadSpecificIoServicePosts&gt;::run_custom_cleanup_function *,boost::detail::do_heap_delete&lt;boost::thread_specific_ptr&lt;Common::ThreadSpecificIoServicePosts&gt;::run_custom_cleanup_function&gt; &gt;::operator delete(void * p=0x002c8870) Line 175 + 0x9 bytes C++ commonTest.exe!boost::detail::sp_counted_impl_pd&lt;boost::thread_specific_ptr&lt;Common::ThreadSpecificIoServicePosts&gt;::run_custom_cleanup_function *,boost::detail::do_heap_delete&lt;boost::thread_specific_ptr&lt;Common::ThreadSpecificIoServicePosts&gt;::run_custom_cleanup_function&gt; &gt;::`scalar deleting destructor'() + 0x27 bytes C++ commonTest.exe!boost::detail::sp_counted_base::destroy() Line 66 + 0x22 bytes C++ commonTest.exe!boost::detail::sp_counted_base::weak_release() Line 116 + 0xf bytes C++ commonTest.exe!boost::detail::sp_counted_base::release() Line 105 C++ commonTest.exe!boost::detail::shared_count::~shared_count() Line 220 C++ commonTest.exe!boost::shared_ptr&lt;boost::detail::tss_cleanup_function&gt;::~shared_ptr&lt;boost::detail::tss_cleanup_function&gt;() + 0x19 bytes C++ commonTest.exe!boost::detail::tss_data_node::~tss_data_node() + 0x12 bytes C++ commonTest.exe!boost::detail::tss_data_node::`scalar deleting destructor'() + 0xf bytes C++ commonTest.exe!boost::detail::heap_delete&lt;boost::detail::tss_data_node&gt;(boost::detail::tss_data_node * data=0x00054ad8) Line 380 C++ commonTest.exe!boost::`anonymous namespace'::run_thread_exit_callbacks() Line 140 + 0x9 bytes C++ commonTest.exe!on_thread_exit() Line 580 C++ msvcr80d.dll!doexit(int code=201, int quick=0, int retcaller=0) Line 553 C msvcr80d.dll!exit(int code=201) Line 398 + 0xd bytes C commonTest.exe!__tmainCRTStartup() Line 610 C commonTest.exe!mainCRTStartup() Line 414 C </pre><p> Is there any more information I can supply to help debugging this problem? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Fri, 05 Sep 2008 22:43:24 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/2217#comment:6 https://svn.boost.org/trac10/ticket/2217#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> I believe I have addressed a coding error in the unregistering of types as DLLs are or main programs are unloaded. I've checked the fix in the trunk. However, none of the test platforms have manifested this error, so it will by up to you test this when it migrates to the release branch. </p> <p> Robert Ramey </p> Ticket Ross Lippert <ross.lippert@…> Fri, 12 Sep 2008 19:51:35 GMT <link>https://svn.boost.org/trac10/ticket/2217#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:7</guid> <description> <p> While I believe that the iterator invalidation issues were important for this problem, this issue should be reopened, because the story does not end there. </p> <p> I believe that the 1.36 implementation of extended_type_info_typeid suffers from a static destructor fiasco. In particular, the tkmap singleton which is local to the extended_type_info_typeid.cpp file, functioning as a registry of type info, can be accessed by typeid destructors after the tkmap has been destructed. </p> <p> I have not been able to produce a small example, and I doubt that any example I could produce would behave likewise across gcc versions. However, I did instrument my code well enough to make a solid case. </p> <p> It began with </p> <pre class="wiki">*** glibc detected *** free(): invalid pointer: 0x00002b3004540dc0 *** </pre><p> at exit. </p> <p> Running the program in valgrind produced, as the first error, </p> <pre class="wiki">==20744== Invalid read of size 8 ==20744== at 0x5DC69BC: std::_Rb_tree&lt;boost::serialization::detail::extended_ type_info_typeid_0 const*, boost::serialization::detail::extended_type_info_type id_0 const*, std::_Identity&lt;boost::serialization::detail::extended_type_info_typ eid_0 const*&gt;, boost::serialization::detail::type_compare, std::allocator&lt;boost: :serialization::detail::extended_type_info_typeid_0 const*&gt; &gt;::lower_bound(boost ::serialization::detail::extended_type_info_typeid_0 const* const&amp;) (stl_tree.h: 1371) ==20744== by 0x5DC673A: boost::serialization::detail::extended_type_info_typeid_0::type_unregister() (stl_multiset.h:451) ==20744== by 0x40DA49: __tcf_12 (extended_type_info_typeid.hpp:85) ==20744== by 0x3759830CD4: exit (in /lib64/tls/libc-2.3.4.so) ==20744== by 0x375981C4C1: (below main) (in /lib64/tls/libc-2.3.4.so) ==20744== Address 0x6EE09B0 is 32 bytes inside a block of size 40 free'd ==20744== at 0x4905D7A: operator delete(void*) (vg_replace_malloc.c:244) ==20744== by 0x5DC6D37: std::_Rb_tree&lt;boost::serialization::detail::extended_type_info_typeid_0 const*, boost::serialization::detail::extended_type_info_typeid_0 const*,std::_Identity&lt;boost::serialization::detail::extended_type_info_typeid_0const*&gt;, oost::serialization::detail::type_compare, std::allocator&lt;boost::serialization::detail::extended_type_info_typeid_0 const*&gt;&gt;::_M_erase(std::_Rb_tree_node&lt;boost::serialization::detail::extended_type_info_typeid_0 const*&gt;*) (new_allocator.h:94) ==20744== by 0x5DC63E8: __tcf_0 (stl_tree.h:578) ==20744== by 0x3759830FBA: __cxa_finalize (in /lib64/tls/libc-2.3.4.so) ==20744== by 0x5DC6242: (within /d/en/lippertr-0/p4/desmond/desmond2_lippertr/base/objs/Linux/x86_64/Release/lib/libdesmond_util.so) ==20744== by 0x5E46AE0: (within /d/en/lippertr-0/p4/desmond/desmond2_lippertr/base/objs/Linux/x86_64/Release/lib/libdesmond_util.so) ==20744== by 0x3759830CD4: exit (in /lib64/tls/libc-2.3.4.so) ==20744== by 0x375981C4C1: (below main) (in /lib64/tls/libc-2.3.4.so) </pre><p> As we see, the underlying rep of the tkmap is corrupt or invalid because lower_bound is failing (this version of 1.36 includes the patches already mentioned). </p> <p> With a little bit of effort, I recompiled boost serialization to have a destructor for the tkmap which prints to the screen and put print messages in the extended_type_info_typeids. </p> <pre class="wiki">in typeid destructor unregistering m_key= 0x5f6ef20 N71_GLOBAL__N_desmond_src_util_timekeeper_timekeeper.cxx_00000000_435F3CA51_E done unregistering. done destructor. tkmap is destroyed! in typeid destructor unregistering m_key= 0x517220 N3Ark3arkE ==20744== Invalid read of size 8 . . . </pre><p> My subsequent prints show that the tkmap is being destructed in the middle of a series of extended_type_info_typeid destructions. This is the static destructor fiasco. The initializer fiasco is overcome by the usual function-scoped static trick, but destructor calls are not so easily serialized. When a destructor has to talk to an instance of another object, you have to be sure that object hasn't destructed yet. </p> <p> To further test, I altered the tkmap implementation to set a live bit. </p> <pre class="wiki">(in extended_type_info_typeid.cpp struct tkmap : std::multiset&lt; const extended_type_info_typeid_0 *, type_compare &gt; { static int live; tkmap() { live=1; } ~tkmap() { live=0; std::cerr &lt;&lt; "tkmap is destroyed!" &lt;&lt; std::endl; } }; int tkmap::live=0; </pre><p> and added </p> <pre class="wiki"> if (!tkmap::live) return; </pre><p> to the type_unregister method. </p> <pre class="wiki">in typeid destructor unregistering m_key= 0x5f6ef40 N71_GLOBAL__N_desmond_src_util_timekeeper_timekeeper.cxx_00000000_435F3CA51_E done unregistering. done destructor. tkmap is destroyed! in typeid destructor unregistering m_key= 0x517220 N3Ark3arkE done destructor. in typeid destructor unregistering m_key= 0x517ec0 N7Desmond6EngineE done destructor. ==21051== ==21051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 9 from 4) </pre><p> I believe that this makes for a substantial case that the addition of tkmap to boost 1.36 (not in 1.35) needs to be rethought. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Tue, 16 Sep 2008 19:23:07 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2217#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:8</guid> <description> <p> Thanks for looking into this. </p> <p> This is a fix I orginally made - but I took it when the iterator mistake was pointed out to me. I had hoped that the order of distructor invocation would be the inverse of constructor invocation - but I guess that is not the case in all compilers. I'm surprised that this is so hard to reproduce. In any case, we'll add in this fix which should fix this case and does no harm anywhere else. </p> <p> Thanks again. </p> <p> Robert Ramey </p> </description> <category>Ticket</category> </item> <item> <author>eric.woodruff@…</author> <pubDate>Wed, 09 Sep 2009 04:39:57 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2217#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2217#comment:9</guid> <description> <p> FYI - I needed to alter the tkmap implementation as suggested by Ross Lippert in 1.39, but it appears in 1.40 I'm not reproducing the problem. </p> </description> <category>Ticket</category> </item> </channel> </rss>