Boost C++ Libraries: Ticket #4415: Posible "Segmentation Fault" in shared_ptr destructor https://svn.boost.org/trac10/ticket/4415 <p> Hi, </p> <p> I got Segmentation Fault as follows, and found a possible bug. </p> <pre class="wiki">Program terminated with signal 11, Segmentation fault. #0 0x0000000000401227 in boost::detail::atomic_exchange_and_add (pw=Cannot access memory at address 0x7fff2ee2dff8 ) at /home/takenori/workspace_native/Boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:36 36 { (gdb) bt #0 0x0000000000401227 in boost::detail::atomic_exchange_and_add (pw=Cannot access memory at address 0x7fff2ee2dff8 ) at /home/takenori/workspace_native/Boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:36 #1 0x000000000040137b in boost::detail::sp_counted_base::release ( this=0xd921130) at /home/takenori/workspace_native/Boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:143 #2 0x000000000040142b in boost::detail::shared_count::~shared_count ( this=0xd9210c0, __in_chrg=&lt;value optimized out&gt;) at /home/takenori/workspace_native/Boost/boost/smart_ptr/detail/shared_count.hpp:217 #3 0x00000000004014be in boost::shared_ptr&lt;SPIntSLLNode&gt;::~shared_ptr ( this=0xd9210b8, __in_chrg=&lt;value optimized out&gt;) at /home/takenori/workspace_native/Boost/boost/smart_ptr/shared_ptr.hpp:163 </pre><p> Here's I doubt. </p> <pre class="wiki"> ~shared_count() // nothrow { if( pi_ != 0 ) pi_-&gt;release(); #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) id_ = 0; #endif } </pre><p> sp_count_base </p> <pre class="wiki"> void release() // nothrow { if( atomic_exchange_and_add( &amp;use_count_, -1 ) == 1 ) { dispose(); weak_release(); } } </pre><p> The two last threads can enter release(), the latter encounters Segmentation Fault on &amp;use_count_. </p> <p> Fairly large singly linked list with shared_ptr easily reproduce this issue at its destruction. </p> <p> Cheers, Takenori </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/4415 Trac 1.4.3 Peter Dimov Fri, 09 Jul 2010 08:43:16 GMT <link>https://svn.boost.org/trac10/ticket/4415#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:1</guid> <description> <p> If two threads enter release, the initial value of use_count_ must be at least 2, and only the thread that last decrements it will proceed to dispose(). I don't see how this can lead to the other thread suffering a segmentation fault while accessing use_count_, as its access must already have been performed. Can you please attach a reasonably complete example that demonstrates the problem? </p> </description> <category>Ticket</category> </item> <item> <author>Takenori Sato <takenori.sato@…></author> <pubDate>Fri, 09 Jul 2010 09:20:33 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/4415 https://svn.boost.org/trac10/ticket/4415 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">SharedPtrCrushTest.cpp</span> </li> </ul> Ticket Takenori Sato <takenori.sato@…> Fri, 09 Jul 2010 09:31:39 GMT <link>https://svn.boost.org/trac10/ticket/4415#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:2</guid> <description> <p> Here's a trivial crush test with singly linked list. </p> <p> I agree the logic looks correct. But it crushes. </p> <p> In my test, the same logic actually works, and runs fine on the same test. </p> <pre class="wiki"> if(counter-&gt;decrement() == 0){ delete counter; delete pointee_; } </pre><p> With the following two implementations. </p> <pre class="wiki"> unsigned int decrement(){ return i.fetch_sub( 1, std::memory_order_relaxed ); } unsigned int decrement(){ assert(pthread_mutex_lock(&amp;mutex) == 0); i++; assert(pthread_mutex_unlock(&amp;mutex) == 0); return i; } </pre><p> I'm not familier with assembly, but is it really atomic? </p> <pre class="wiki"> __asm__ __volatile__ ( "lock\n\t" "xadd %1, %0": "=m"( *pw ), "=r"( r ): // outputs (%0, %1) "m"( *pw ), "1"( dv ): // inputs (%2, %3 == %1) "memory", "cc" // clobbers ); </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Fri, 09 Jul 2010 10:05:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:3</guid> <description> <p> Yes, lock xadd is atomic. What version of g++ are you using, and what optimization level? There are no threads in your example, so it's probably a code generation problem. </p> </description> <category>Ticket</category> </item> <item> <author>Takenori Sato <takenori.sato@…></author> <pubDate>Fri, 09 Jul 2010 11:00:54 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:4</guid> <description> <p> I used two versions, the same results. 4.1.2 and 4.4.0. </p> <p> The build script I used is the following. </p> <pre class="wiki">gcc -g -Iinc -IBoost -c -o bin/SharedPtrCrushTest.o src/SharedPtrCrushTest.cpp gcc -g -lstdc++ -o bin/SharedPtrCrushTest bin/SharedPtrCrushTest.o </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Fri, 09 Jul 2010 11:24:56 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:5</guid> <description> <p> Does it make any difference if you use g++ instead of gcc? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Fri, 09 Jul 2010 11:36:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:6</guid> <description> <p> FWIW, your program works for me with g++ 4.3.4 under <a class="missing wiki">Windows/Cygwin</a>. I have verified that the assembly contains the portions from sp_counted_base_gcc_x86.hpp. What OS are you using? </p> </description> <category>Ticket</category> </item> <item> <author>Takenori Sato <takenori.sato@…></author> <pubDate>Fri, 09 Jul 2010 12:23:09 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:7</guid> <description> <p> Thanks for checking. </p> <p> No, g++ didn't make any difference. </p> <p> My OS is CentOS 5.5(final). Kernel is 2.6.18. CPU is Core 2 Duo P7350 @2GHz(64bit). </p> <p> Could 64bit make any difference? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Fri, 09 Jul 2010 13:24:59 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:8</guid> <description> <p> I can reproduce the crash under CentOS 5.4. It is not a 64 bit issue, as g++ -m32 crashes as well. I don't know yet what's causing it or whether the problem is in our code or a Red Hat g++ issue. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 09 Jul 2010 14:05:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:9</guid> <description> <p> I get it crushed also on Max OS X(10.6.4), gcc 4.2.1. </p> <p> But on Windows with Cygwin, it doesn't. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Fri, 09 Jul 2010 14:11:36 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:10</guid> <description> <p> It is a stack overflow due to the 1000000 recursive destructor calls. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 09 Jul 2010 16:07:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:11</guid> <description> <p> Oops! </p> <p> Is there any reason that this happens only with shared_ptr? </p> <p> I mean, two other implementations with c++0x atomic operations and mutex don't fail. </p> <p> Anyway, I check stack myself. Thanks. </p> </description> <category>Ticket</category> </item> <item> <author>Takenori Sato <takenori.sato@…></author> <pubDate>Sat, 10 Jul 2010 02:47:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:12</guid> <description> <p> This was completely my fault. I found some leaks that was considered working, which didn't call destructor recursively. </p> <p> Thanks. </p> </description> <category>Ticket</category> </item> <item> <author>Takenori Sato <takenori.sato@…></author> <pubDate>Sat, 10 Jul 2010 04:27:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4415#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4415#comment:13</guid> <description> <p> For those who have the same problem. One little change solves this issue. </p> <pre class="wiki"> ~IntSLList(){ while(head != tail){ // replace head = head-&gt;next; } } </pre><p> shared_ptr carefully manages counter, so this does not trigger recursive destruction. </p> <p> This works for millions or whatever until exausted. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Peter Dimov</dc:creator> <pubDate>Mon, 12 Jul 2010 09:37:08 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/4415#comment:14 https://svn.boost.org/trac10/ticket/4415#comment:14 <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">invalid</span> </li> </ul> Ticket