Boost C++ Libraries: Ticket #3080: dynamic_cast returns 0 on polymorphic serialization with weak_ptr https://svn.boost.org/trac10/ticket/3080 <h3 class="section" id="Problem">Problem</h3> <p> In multiple inheritance case, after de-serialization, failed to dynamic_cast from a data member polymorphic serialize via 2nd base class (Left) to subclass (Bottom). </p> <div class="wiki-code"><div class="code"><pre> <span class="c1">// check</span> <span class="n">Left</span> <span class="o">*</span><span class="n">pLeft</span> <span class="o">=</span> <span class="n">h2</span><span class="p">.</span><span class="n">mbl_</span><span class="p">.</span><span class="n">get</span><span class="p">();</span> <span class="n">Bottom</span> <span class="o">*</span><span class="n">pBottomFromLeft</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Bottom</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">pLeft</span><span class="p">);</span> <span class="n">Right</span> <span class="o">*</span><span class="n">pRight</span> <span class="o">=</span> <span class="n">h2</span><span class="p">.</span><span class="n">mbr_</span><span class="p">.</span><span class="n">get</span><span class="p">();</span> <span class="n">Bottom</span> <span class="o">*</span><span class="n">pBottomFromRight</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Bottom</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">pRight</span><span class="p">);</span> <span class="n">assert</span><span class="p">(</span><span class="n">pBottomFromLeft</span><span class="p">);</span> <span class="c1">// Success</span> <span class="n">assert</span><span class="p">(</span><span class="n">pBottomFromRight</span><span class="p">);</span> <span class="c1">// Fail. Comment out *1 and *2, it works corrctly.</span> </pre></div></div><h3 class="section" id="Myanalysis">My analysis</h3> <p> Class 'Bottom' has weak_ptr that point to itself. When weak_ptr member wp_ exclude serialization, dynamic_cast is success.(Comment out *1 and *2 lines.) </p> <p> I set break point (using gdb). =&gt; is position. </p> <div class="wiki-code"><div class="code"><pre><span class="k">class</span> <span class="nc">Holder</span> <span class="p">{</span> <span class="k">public</span><span class="o">:</span> <span class="n">LeftSp</span> <span class="n">mbl_</span><span class="p">;</span> <span class="c1">// shared_ptr&lt;Left&gt;</span> <span class="n">RightSp</span> <span class="n">mbr_</span><span class="p">;</span> <span class="c1">// shared_ptr&lt;Right&gt;</span> <span class="n">Holder</span><span class="p">()</span> <span class="p">{}</span> <span class="c1">// for serialize</span> <span class="n">Holder</span><span class="p">(</span><span class="n">BottomSp</span> <span class="n">l</span><span class="p">,</span> <span class="n">BottomSp</span> <span class="n">r</span><span class="p">)</span><span class="o">:</span><span class="n">mbl_</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="p">,</span><span class="n">mbr_</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="p">{}</span> <span class="c1">// for appli construct</span> <span class="c1">// serialize</span> <span class="k">friend</span> <span class="k">class</span> <span class="nc">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">access</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">save</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&amp;</span><span class="n">ar</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="cm">/* file_version */</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="c1">// polymophic serialize via shared_ptr</span> <span class="n">ar</span> <span class="o">&lt;&lt;</span> <span class="n">BOOST_SERIALIZATION_NVP</span><span class="p">(</span><span class="n">mbl_</span><span class="p">);</span> <span class="c1">// polymophic serialize via shared_ptr</span> <span class="n">ar</span> <span class="o">&lt;&lt;</span> <span class="n">BOOST_SERIALIZATION_NVP</span><span class="p">(</span><span class="n">mbr_</span><span class="p">);</span> <span class="p">}</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">load</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&amp;</span> <span class="n">ar</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="cm">/* file_version */</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// polymophic de-serialize via shared_ptr</span> <span class="n">ar</span> <span class="o">&gt;&gt;</span> <span class="n">BOOST_SERIALIZATION_NVP</span><span class="p">(</span><span class="n">mbl_</span><span class="p">);</span> <span class="c1">// polymophic de-serialize via shared_ptr</span> <span class="n">ar</span> <span class="o">&gt;&gt;</span> <span class="n">BOOST_SERIALIZATION_NVP</span><span class="p">(</span><span class="n">mbr_</span><span class="p">);</span> <span class="o">=&gt;</span> <span class="p">}</span> <span class="n">BOOST_SERIALIZATION_SPLIT_MEMBER</span><span class="p">()</span> <span class="p">};</span> </pre></div></div><p> And, I printed below values. </p> <p> In assertion failed case, _vptr.Left is equal to _vptr.Right. </p> <pre class="wiki">(gdb) p *mbl_.px $1 = {_vptr.Left = 0x8060ba8} (gdb) p *mbr_.px $1 = {_vptr.Right = 0x8060ba8} </pre><p> But, success case (remove the member wp_'s serialization), _vptr.Left is not equal to _vptr.Right </p> <pre class="wiki">(gdb) p *mbl_.px $1 = {_vptr.Left = 0x805d1e8} (gdb) p *mbr_.px $1 = {_vptr.Right = 0x805d1f8} </pre><h3 class="section" id="Environment">Environment</h3> <p> g++ (Gentoo 4.3.2-<a class="changeset" href="https://svn.boost.org/trac10/changeset/3" title="Tweak disclaimer text">r3</a> p1.6, pie-10.1.5) 4.3.2 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3080 Trac 1.4.3 Takatoshi Kondo <kondo@…> Mon, 25 May 2009 13:28:12 GMT attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">wps.cpp</span> </li> </ul> <p> Sample program that operates completely that reproduces bug. </p> Ticket Takatoshi Kondo <kondo@…> Mon, 25 May 2009 14:15:28 GMT attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">ClassDiagram.png</span> </li> </ul> <p> Class structure </p> Ticket Takatoshi Kondo <kondo@…> Sat, 30 May 2009 00:30:17 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:1</guid> <description> <p> I analyzed this problem. And, I finally noticed. </p> <p> Now, I have understood data member m_pointers in the shared_ptr_helper class keep information by the type shared_ptr&lt;void&gt; to achieve the restoration shared. </p> <p> The behavior of wps.c (Attached file) is same as the following simple sample. </p> <div class="wiki-code"><div class="code"><pre><span class="k">class</span> <span class="nc">Left</span> <span class="p">{</span> <span class="k">public</span><span class="o">:</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Left</span><span class="p">()</span> <span class="p">{}</span> <span class="p">};</span> <span class="k">class</span> <span class="nc">Right</span> <span class="p">{</span> <span class="k">public</span><span class="o">:</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Right</span><span class="p">()</span> <span class="p">{}</span> <span class="p">};</span> <span class="k">class</span> <span class="nc">Bottom</span><span class="o">:</span><span class="k">public</span> <span class="n">Left</span><span class="p">,</span> <span class="k">public</span> <span class="n">Right</span> <span class="p">{</span> <span class="k">public</span><span class="o">:</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Bottom</span><span class="p">()</span> <span class="p">{}</span> <span class="p">};</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="n">Bottom</span> <span class="n">b</span><span class="p">;</span> <span class="kt">void</span> <span class="o">*</span><span class="n">pv</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">b</span><span class="p">;</span> <span class="n">Right</span> <span class="o">*</span><span class="n">pr2</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">Right</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">pv</span><span class="p">);</span> <span class="n">assert</span><span class="p">(</span><span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Bottom</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">pr2</span><span class="p">));</span> <span class="c1">// Fail</span> <span class="p">}</span> </pre></div></div><p> The meaning of static_cast in this sample is same as the following code. <a class="ext-link" href="https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L132"><span class="icon">​</span>https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L132</a> </p> <p> In deserializing weak_ptr, it is inserted to m_pointers as shared_ptr&lt;void&gt;. <a class="ext-link" href="https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L129"><span class="icon">​</span>https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L129</a> </p> <p> Afterwards, when deserializing the shared_ptr, the following code is executed. <a class="ext-link" href="https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L132"><span class="icon">​</span>https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp#L132</a> </p> <p> Then, the problem occurs because the type of shared_ptr is 'Right' the second base class of 'Bottom'. </p> <hr /> <p> I checked the document again. </p> <p> I had overlooked the following part of the document. </p> <p> <a href="http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/new_case_studies.html#archivehelper">http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/new_case_studies.html#archivehelper</a> </p> <p> I'm not sure this problem is same as the current archive helper limitation. However, if it is exactly correct, this ticket should not be a bug but should be a feature requests. </p> <p> Could you give me your feedback? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Sohail Somani</dc:creator> <pubDate>Sat, 30 May 2009 01:48:15 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:2</guid> <description> <p> The sample code you post looks to be incorrect. Specifically, you can't cast from T* to void* and back to anything but T*. This will especially apply in multiple inheritance. I think to do anything further on this bug, a better test case needs to be given. Specifically one that we can compile and see failing. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Sohail Somani</dc:creator> <pubDate>Sat, 30 May 2009 01:48:52 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/3080#comment:3 https://svn.boost.org/trac10/ticket/3080#comment:3 <ul> <li><strong>cc</strong> <span class="trac-author">Sohail Somani</span> added </li> </ul> Ticket Takatoshi Kondo <kondo@…> Sat, 30 May 2009 02:53:39 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:4</guid> <description> <p> I'm sorry for being confused. </p> <p> <a class="ext-link" href="https://svn.boost.org/trac/boost/ticket/3080#comment:1"><span class="icon">​</span>https://svn.boost.org/trac/boost/ticket/3080#comment:1</a> is not a sample that works correctly. </p> <p> The motivation of this sample is describe behavior of shared_ptr_hepler. </p> <div class="wiki-code"><div class="code"><pre> <span class="mi">56</span> <span class="k">class</span> <span class="nc">shared_ptr_helper</span> <span class="p">{</span> <span class="mi">57</span> <span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">shared_ptr</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">collection_type</span><span class="p">;</span> <span class="mi">58</span> <span class="k">typedef</span> <span class="n">collection_type</span><span class="o">::</span><span class="n">const_iterator</span> <span class="n">iterator_type</span><span class="p">;</span> <span class="mi">59</span> <span class="c1">// list of shared_pointers create accessable by raw pointer. This</span> <span class="mi">60</span> <span class="c1">// is used to &quot;match up&quot; shared pointers loaded at different</span> <span class="mi">61</span> <span class="c1">// points in the archive. Note, we delay construction until</span> <span class="mi">62</span> <span class="c1">// it is actually used since this is by default included as</span> <span class="mi">63</span> <span class="c1">// a &quot;mix-in&quot; even if shared_ptr isn&#39;t used.</span> <span class="mi">64</span> <span class="n">collection_type</span> <span class="o">*</span> <span class="n">m_pointers</span><span class="p">;</span> <span class="n">snip</span> <span class="p">...</span> <span class="mi">111</span> <span class="k">public</span><span class="o">:</span> <span class="mi">112</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="o">&gt;</span> <span class="mi">113</span> <span class="kt">void</span> <span class="n">reset</span><span class="p">(</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="n">T</span> <span class="o">*</span> <span class="n">r</span><span class="p">){</span> <span class="mi">114</span> <span class="k">if</span><span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">r</span><span class="p">){</span> <span class="mi">115</span> <span class="n">s</span><span class="p">.</span><span class="n">reset</span><span class="p">();</span> <span class="mi">116</span> <span class="k">return</span><span class="p">;</span> <span class="mi">117</span> <span class="p">}</span> <span class="mi">118</span> <span class="c1">// get pointer to the most derived object. This is effectively</span> <span class="mi">119</span> <span class="c1">// the object identifer</span> <span class="mi">120</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span> <span class="n">od</span> <span class="o">=</span> <span class="n">object_identifier</span><span class="p">(</span><span class="n">r</span><span class="p">);</span> <span class="mi">121</span> <span class="mi">122</span> <span class="nf">if</span><span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">m_pointers</span><span class="p">)</span> <span class="mi">123</span> <span class="n">m_pointers</span> <span class="o">=</span> <span class="k">new</span> <span class="n">collection_type</span><span class="p">;</span> <span class="mi">124</span> <span class="mi">125</span> <span class="n">iterator_type</span> <span class="n">it</span> <span class="o">=</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">find</span><span class="p">(</span><span class="n">od</span><span class="p">);</span> <span class="mi">126</span> <span class="mi">127</span> <span class="nf">if</span><span class="p">(</span><span class="n">it</span> <span class="o">==</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">end</span><span class="p">()){</span> <span class="mi">128</span> <span class="n">s</span><span class="p">.</span><span class="n">reset</span><span class="p">(</span><span class="n">r</span><span class="p">);</span> <span class="mi">129</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">insert</span><span class="p">(</span><span class="n">collection_type</span><span class="o">::</span><span class="n">value_type</span><span class="p">(</span><span class="n">od</span><span class="p">,</span><span class="n">s</span><span class="p">));</span> <span class="mi">130</span> <span class="p">}</span> <span class="mi">131</span> <span class="k">else</span><span class="p">{</span> <span class="mi">132</span> <span class="n">s</span> <span class="o">=</span> <span class="n">static_pointer_cast</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">((</span><span class="o">*</span><span class="n">it</span><span class="p">).</span><span class="n">second</span><span class="p">);</span> <span class="mi">133</span> <span class="p">}</span> <span class="mi">134</span> <span class="p">}</span> </pre></div></div><p> The sample that reproduces bug is the following. <a class="ext-link" href="https://svn.boost.org/trac/boost/attachment/ticket/3080/wps.cpp"><span class="icon">​</span>https://svn.boost.org/trac/boost/attachment/ticket/3080/wps.cpp</a> </p> <p> And I made more essential following sample(sp_mlt_base.cpp). </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;cassert&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/shared_ptr.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/weak_ptr.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/serialization/serialization.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/archive/xml_oarchive.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/archive/xml_iarchive.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/serialization/nvp.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/serialization/export.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/serialization/shared_ptr.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/serialization/weak_ptr.hpp&gt;</span><span class="cp"></span> <span class="k">struct</span> <span class="n">Base1</span> <span class="p">{</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Base1</span><span class="p">()</span> <span class="p">{}</span> <span class="c1">// serialize</span> <span class="k">friend</span> <span class="k">class</span> <span class="nc">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">access</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&amp;</span> <span class="cm">/*ar*/</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="cm">/* file_version */</span><span class="p">)</span> <span class="p">{}</span> <span class="p">};</span> <span class="n">BOOST_CLASS_EXPORT</span><span class="p">(</span><span class="n">Base1</span><span class="p">)</span> <span class="k">struct</span> <span class="n">Base2</span> <span class="p">{</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Base2</span><span class="p">()</span> <span class="p">{}</span> <span class="c1">// serialize</span> <span class="k">friend</span> <span class="k">class</span> <span class="nc">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">access</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&amp;</span> <span class="cm">/*ar*/</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="cm">/* file_version */</span><span class="p">)</span> <span class="p">{}</span> <span class="p">};</span> <span class="n">BOOST_CLASS_EXPORT</span><span class="p">(</span><span class="n">Base2</span><span class="p">)</span> <span class="k">struct</span> <span class="nl">Sub</span><span class="p">:</span><span class="k">public</span> <span class="n">Base1</span><span class="p">,</span> <span class="k">public</span> <span class="n">Base2</span> <span class="p">{</span> <span class="k">virtual</span> <span class="o">~</span><span class="n">Sub</span><span class="p">()</span> <span class="p">{}</span> <span class="n">boost</span><span class="o">::</span><span class="n">weak_ptr</span><span class="o">&lt;</span><span class="n">Sub</span><span class="o">&gt;</span> <span class="n">wp_</span><span class="p">;</span> <span class="c1">// serialize</span> <span class="k">friend</span> <span class="k">class</span> <span class="nc">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">access</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&amp;</span><span class="n">ar</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="cm">/* file_version */</span><span class="p">)</span> <span class="p">{</span> <span class="n">ar</span> <span class="o">&amp;</span> <span class="n">BOOST_SERIALIZATION_BASE_OBJECT_NVP</span><span class="p">(</span><span class="n">Base1</span><span class="p">);</span> <span class="n">ar</span> <span class="o">&amp;</span> <span class="n">BOOST_SERIALIZATION_BASE_OBJECT_NVP</span><span class="p">(</span><span class="n">Base2</span><span class="p">);</span> <span class="n">ar</span> <span class="o">&amp;</span> <span class="n">BOOST_SERIALIZATION_NVP</span><span class="p">(</span><span class="n">wp_</span><span class="p">);</span> <span class="c1">// *1</span> <span class="p">}</span> <span class="p">};</span> <span class="n">BOOST_CLASS_EXPORT</span><span class="p">(</span><span class="n">Sub</span><span class="p">)</span> <span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span> <span class="p">{</span> <span class="c1">// serialize</span> <span class="n">boost</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Sub</span><span class="o">&gt;</span> <span class="n">s</span><span class="p">(</span><span class="k">new</span> <span class="n">Sub</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Base2</span><span class="o">&gt;</span> <span class="n">pb2</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> <span class="n">s</span><span class="o">-&gt;</span><span class="n">wp_</span> <span class="o">=</span> <span class="n">s</span><span class="p">;</span> <span class="c1">// set weak_ptr. If not set, deserialize success.</span> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span> <span class="n">ofs</span><span class="p">(</span><span class="s">&quot;output.xml&quot;</span><span class="p">);</span> <span class="n">assert</span><span class="p">(</span><span class="n">ofs</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">xml_oarchive</span> <span class="n">oa</span><span class="p">(</span><span class="n">ofs</span><span class="p">);</span> <span class="n">oa</span> <span class="o">&lt;&lt;</span> <span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">make_nvp</span><span class="p">(</span><span class="s">&quot;Base2&quot;</span><span class="p">,</span> <span class="n">pb2</span><span class="p">);</span> <span class="p">}</span> <span class="p">{</span> <span class="c1">// de-serialize</span> <span class="n">std</span><span class="o">::</span><span class="n">ifstream</span> <span class="n">ifs</span><span class="p">(</span><span class="s">&quot;output.xml&quot;</span><span class="p">);</span> <span class="n">assert</span><span class="p">(</span><span class="n">ifs</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">xml_iarchive</span> <span class="n">ia</span><span class="p">(</span><span class="n">ifs</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Base2</span><span class="o">&gt;</span> <span class="n">pb2</span><span class="p">;</span> <span class="n">ia</span> <span class="o">&gt;&gt;</span> <span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">make_nvp</span><span class="p">(</span><span class="s">&quot;Base2&quot;</span><span class="p">,</span> <span class="n">pb2</span><span class="p">);</span> <span class="c1">// check</span> <span class="c1">// pb2&#39;s vptr is broken.</span> <span class="n">assert</span><span class="p">(</span><span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Sub</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">pb2</span><span class="p">.</span><span class="n">get</span><span class="p">()));</span> <span class="p">}</span> <span class="p">}</span> </pre></div></div><p> Please check it. </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Sat, 30 May 2009 02:54:31 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">sp_mlt_base.cpp</span> </li> </ul> Ticket Robert Ramey Sat, 30 May 2009 04:34:05 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:5</guid> <description> <p> Sorry I haven't been able to give this the attention it deserves. I haven't forgotten it, I just haven't had time to look into it. Thanks for your continuing efforts. </p> <p> Robert Ramey </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Sat, 30 May 2009 23:32:37 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test_zmisc.cpp</span> </li> </ul> Ticket Robert Ramey Sat, 30 May 2009 23:35:37 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/3080#comment:6 https://svn.boost.org/trac10/ticket/3080#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">worksforme</span> </li> </ul> <p> I've adjust your test to give me some more information. Compiles, and runs without error on my VC 7.1 system. So one of the following: </p> <p> a) My changes made it pass b) Compiler differences </p> <p> Try this on you system. If it passes, figure out where the difference is. </p> <p> Robert Ramey </p> Ticket Takatoshi Kondo <kondo@…> Sun, 31 May 2009 01:33:59 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:7</guid> <description> <p> Thank you for the reply. </p> <p> I can check on VC++ 9.0.21022.8 RTM and g++ (Gentoo 4.3.2-<a class="changeset" href="https://svn.boost.org/trac10/changeset/3" title="Tweak disclaimer text">r3</a> p1.6, pie-10.1.5) 4.3.2. </p> <p> I will try to check on my environment today. Afterwards, I will comment. </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Sun, 31 May 2009 06:35:43 GMT</pubDate> <title>status changed; resolution deleted https://svn.boost.org/trac10/ticket/3080#comment:8 https://svn.boost.org/trac10/ticket/3080#comment:8 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">worksforme</span> </li> </ul> <h2 class="section" id="Resultoftest_zmisc.cpp">Result of test_zmisc.cpp</h2> <h3 class="section" id="OnVC9.0.21022.8RTM">On VC++ 9.0.21022.8 RTM</h3> <p> Compile successed. </p> <p> Run failed. Access violation occured. pb2_1 is incorrect. </p> <h3 class="section" id="OngGentoo4.3.2-r3p1.6pie-10.1.54.3.2.">On g++ (Gentoo 4.3.2-<a class="changeset" href="https://svn.boost.org/trac10/changeset/3" title="Tweak disclaimer text">r3</a> p1.6, pie-10.1.5) 4.3.2.</h3> <p> Compile successed. Run failed. Access violation occured. pb2_1 is incorrect. </p> <hr /> <p> Same result. </p> <p> I think that these compilers are comparatively new, and major. </p> <p> Could you check your sample and my sample using these compiler? </p> <h2 class="section" id="Myanalysis">My analysis</h2> <p> pb2(original data)'s __vfptr point to vftable for Base2. </p> <p> pb2_1(deserialized)'s __vfptr point to vftavble for Base1. </p> <p> pb2_1's __vfptr should point to vftable for Base2. </p> <p> Why does pb2_1's __vfptr point to vftable for Base1. </p> <p> The reseason is following... </p> <div class="wiki-code"><div class="code"><pre> <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">reset</span><span class="p">(</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="n">T</span> <span class="o">*</span> <span class="n">r</span><span class="p">){</span> <span class="k">if</span><span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">r</span><span class="p">){</span> <span class="n">s</span><span class="p">.</span><span class="n">reset</span><span class="p">();</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// get pointer to the most derived object. This is effectively</span> <span class="c1">// the object identifer</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span> <span class="n">od</span> <span class="o">=</span> <span class="n">object_identifier</span><span class="p">(</span><span class="n">r</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">m_pointers</span><span class="p">)</span> <span class="n">m_pointers</span> <span class="o">=</span> <span class="k">new</span> <span class="n">collection_type</span><span class="p">;</span> <span class="n">iterator_type</span> <span class="n">it</span> <span class="o">=</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">find</span><span class="p">(</span><span class="n">od</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="n">it</span> <span class="o">==</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">end</span><span class="p">()){</span> <span class="n">s</span><span class="p">.</span><span class="n">reset</span><span class="p">(</span><span class="n">r</span><span class="p">);</span> <span class="n">m_pointers</span><span class="o">-&gt;</span><span class="n">insert</span><span class="p">(</span><span class="n">collection_type</span><span class="o">::</span><span class="n">value_type</span><span class="p">(</span><span class="n">od</span><span class="p">,</span><span class="n">s</span><span class="p">));</span> <span class="c1">// point1</span> <span class="p">}</span> <span class="k">else</span><span class="p">{</span> <span class="n">s</span> <span class="o">=</span> <span class="n">static_pointer_cast</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">((</span><span class="o">*</span><span class="n">it</span><span class="p">).</span><span class="n">second</span><span class="p">);</span> <span class="c1">// point2</span> <span class="p">}</span> <span class="p">}</span> </pre></div></div><p> <a class="ext-link" href="https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp"><span class="icon">​</span>https://svn.boost.org/trac/boost/browser/tags/release/Boost_1_39_0/boost/archive/shared_ptr_helper.hpp</a> </p> <ol><li>When m_wp deserialize, program passed point1. </li><li>When pb2_1 deserialize, program passed point2.Because they point to same object. </li></ol><p> After step1, type information was lost. Because the container m_pointers type is shared_ptr&lt;void&gt;. </p> <p> In step2, it is impossible to distinguish that (*it).second is instance of 'Sub' or instance of 'Base2'. </p> <p> Currently, member function reset() considers (*it).second to shared_ptr&lt;Base2&gt;, based on type T. </p> <p> Unfortunately the real object type is 'Sub'. </p> <p> After all, writing position for the desirializing data was shifted. And pb2_1 was broken. </p> Ticket Robert Ramey Sun, 31 May 2009 16:51:32 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:9</guid> <description> <p> Well you've certainly done your homework! Thanks for taking this time. I'll look into it. </p> <p> Robert Ramey </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Sun, 07 Jun 2009 13:52:22 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">shared_ptr_mlt_inh.patch</span> </li> </ul> <p> patch to solve this problem </p> Ticket Takatoshi Kondo <kondo@…> Sun, 07 Jun 2009 13:59:56 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:10</guid> <description> <p> I made the patch to solve this problem. (shared_ptr_mlt_inh.patch ) </p> <p> It seems to have solved the problem. </p> <p> The point that had been devised with this patch combined void_upcast and aliasing constructor of shared_ptr well. </p> <p> I am doing regression test preparation, it doesn't complete yet. </p> <p> There are many tests in /boost_1_39_0/libs/serialization/test. </p> <p> I do not understand still how to do the regression test though I'm reading the document. </p> <p> Please review my patch. And could you teach me how to build the regression test? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Sun, 07 Jun 2009 17:50:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:11</guid> <description> <p> I've been working on this problem and have found no way to fix it in a definitive manner. A definitive fix would require enhancements in the shared_ptr public interface which I don't expect to occur. </p> <p> The problem can be addressed in the test case: </p> <pre class="wiki">struct Sub:public Base1, public Base2 { int m_x; boost::weak_ptr&lt;Sub&gt; m_wp; //fails //boost::weak_ptr&lt;Base2&gt; m_wp; //OK Sub(){} Sub(int x) : Base1(x), Base2(x), m_x(x) {} </pre><p> By using only one type of pointer to serialize the same object. This problem only occurs when using shared pointer and it's friends. </p> <p> I've updated the code to trap the condition and throw an exception when it is discovered. </p> <p> I've looked at your patch. First, I'm very impressed that you've clearly understood how share_ptr_helper works and what it does. And this is without any explanation and documentation!!!. </p> <p> At first I was inclined to dismiss it as I had spent a lot of time only to conclude that it wasn't fixable. Looking carefully at your code - which looks very similar to my own attempts, now I'm thinking you might be right. So I'm still looking at it. The problem for me is that the shared_ptr operations in the public interface are not all that transparent to me. </p> <p> As for testing, I would expect that a much simpler test could be made. </p> <pre class="wiki"> class Base { ... }; class Derived : public Base { ... } smart_ptr dptr = new Derived; smart_ptr bptr = dptr; // now there is only one object with pointers of different types ... ar &gt;&gt; dptr; ar &gt;&gt; bptr; // creates problem. // dptr and bptr point to the same object </pre><p> Anyway, I'm going to study your patch in more detail. </p> <p> Robert Ramey. </p> <p> PS - unfortunately, I had alread conclude that this was not fixable and had updated the manual and exception list accordingly. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Sun, 07 Jun 2009 17:51:33 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:12</guid> <description> <p> As to building a regression test, just take one of the examples in the test directory and modify it to your own test. </p> <p> RR </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Sun, 07 Jun 2009 18:19:19 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:13</guid> <description> <p> Damn - </p> <p> Looks like your solution is exactly the correct one. </p> <p> I would like to see a more exhaustive test which would test the variations on share_ptr and weak_ptr of shared objects. </p> <p> Robert Ramey </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Mon, 08 Jun 2009 22:17:59 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:14</guid> <description> <p> Thanks! </p> <p> I am glad to contribute to your library. </p> <p> I am looking forward to result of the exhaustive test. </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Thu, 11 Jun 2009 14:16:35 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test_shared_ptr_multi_base.cpp</span> </li> </ul> <p> <a class="missing wiki">TestCode</a> </p> Ticket Takatoshi Kondo <kondo@…> Thu, 11 Jun 2009 14:17:15 GMT attachment set https://svn.boost.org/trac10/ticket/3080 https://svn.boost.org/trac10/ticket/3080 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">add_test.patch</span> </li> </ul> <p> Add test to Jamfile.v2 in serialization </p> Ticket Takatoshi Kondo <kondo@…> Thu, 11 Jun 2009 14:44:28 GMT <link>https://svn.boost.org/trac10/ticket/3080#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:15</guid> <description> <p> I made a test code based on test_shared_ptr.cpp, adn ran it. </p> <p> The test file name is <a class="ext-link" href="https://svn.boost.org/trac/boost/attachment/ticket/3080/test_shared_ptr_multi_base.cpp"><span class="icon">​</span>test_shared_ptr_multi_base.cpp</a>. </p> <p> I think that this file is added to /libs/serialization/test directory. </p> <p> And <a class="ext-link" href="https://svn.boost.org/trac/boost/attachment/ticket/3080/add_test.patch"><span class="icon">​</span>add_test.patch</a> is patch for Jamfile.v2 to add the test file to automatic test process. </p> <p> Before shared_ptr_mlt_inh.patch, There ware 3 failures. And test program exited on exception. Actually though there is a failure more. </p> <p> I have not understood the method of doing so though it is thought that all failures should be able to be counted. </p> <p> But I think it is not so big problem. </p> <p> After shared_ptr_mlt_inh.patch, There is no failure. </p> <p> Is this exhaustive enough? </p> <p> If you don't think so, Please point out the viewpoint of the test that should be added. </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Thu, 11 Jun 2009 14:56:19 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:16</guid> <description> <p> After that, I did the regression tests of serialization, and there is no failure detected. </p> </description> <category>Ticket</category> </item> <item> <author>Takatoshi Kondo <kondo@…></author> <pubDate>Wed, 17 Jun 2009 23:13:43 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3080#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3080#comment:17</guid> <description> <p> Hi. </p> <p> The milestone of this ticket is 1.40.0. And the next release day is getting closer. </p> <p> <a class="ext-link" href="https://svn.boost.org/trac/boost/wiki/ReleaseSchedule"><span class="icon">​</span>https://svn.boost.org/trac/boost/wiki/ReleaseSchedule</a> </p> <p> Will my patch merge to the next release? </p> <p> I already did the tests. </p> <p> Should I do anything? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Thu, 09 Jul 2009 15:00:05 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3080#comment:18 https://svn.boost.org/trac10/ticket/3080#comment:18 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Fixed in the trunk due in large part to your efforts. Thank you. </p> Ticket