Boost C++ Libraries: Ticket #3585: Boost::thread + valgrind/drd possible false positive https://svn.boost.org/trac10/ticket/3585 <p> OS: Arch Linux </p> <p> Boost Library v 1.39 </p> <p> Valgrind v 3.5 </p> <p> Problem description: </p> <p> Running small degenerated piece of code under valgrind/drd produces "probably a race condition" error on call of "interrupt". I was adviced on #boost channel to make a ticket after short examination of code. </p> <p> Note: </p> <p> This [ <a class="ext-link" href="https://svn.boost.org/trac/boost/ticket/3526"><span class="icon">​</span>https://svn.boost.org/trac/boost/ticket/3526</a> ] case was added to valgrind suppression file. </p> <p> Example code attached. </p> <p> Compilation: </p> <pre class="wiki">make all Building file: ../src/test.cpp Invoking: GCC C++ Compiler g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/test.d" -MT"src/test.d" -o"src/test.o" "../src/test.cpp" Finished building: ../src/test.cpp Building target: test Invoking: GCC C++ Linker g++ -o"test" ./src/test.o -lboost_thread-mt Finished building target: test </pre><p> Output: </p> <pre class="wiki">[mist@fog test]$ valgrind --tool=drd ./Debug/test ==2759== drd, a thread error detector ==2759== Copyright (C) 2006-2009, and GNU GPL'd, by Bart Van Assche. ==2759== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info ==2759== Command: ./Debug/test ==2759== ==2759== Probably a race condition: condition variable 0x5f64180 has been signaled but the associated mutex 0x5f64158 is not locked by the signalling thread. ==2759== at 0x4C27BF9: pthread_cond_broadcast@* (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so) ==2759== by 0x4E3BC88: boost::thread::interrupt() (in /usr/lib/libboost_thread-mt.so.1.39.0) ==2759== by 0x405D42: stopThread(std::string const&amp;) (test.cpp:45) ==2759== by 0x405E79: main (test.cpp:75) ==2759== cond 0x5f64180 was first observed at: ==2759== at 0x4C266D9: pthread_cond_init@* (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so) ==2759== by 0x406E0B: boost::condition_variable::condition_variable() (condition_variable_fwd.hpp:30) ==2759== by 0x406F39: boost::detail::thread_data_base::thread_data_base() (thread_data.hpp:54) ==2759== by 0x40BF1C: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;::thread_data(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;) (thread.hpp:48) ==2759== by 0x40B7F1: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;* boost::detail::heap_new_impl&lt;boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;, boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;&gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;) (thread_heap_alloc.hpp:47) ==2759== by 0x40AA8B: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;* boost::detail::heap_new&lt;boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;, boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;) (thread_heap_alloc.hpp:73) ==2759== by 0x40A1C0: boost::shared_ptr&lt;boost::detail::thread_data_base&gt; boost::thread::make_thread_info&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;) (thread.hpp:136) ==2759== by 0x4092E1: boost::thread::thread&lt;cTestRunner, std::string&gt;(cTestRunner, std::string) (thread.hpp:227) ==2759== by 0x407D28: void startThread&lt;cTestRunner&gt;(std::string const&amp;) (test.cpp:36) ==2759== by 0x405DDB: main (test.cpp:71) ==2759== mutex 0x5f64158 was first observed at: ==2759== at 0x4C2C04F: pthread_mutex_init (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so) ==2759== by 0x406D31: boost::mutex::mutex() (mutex.hpp:37) ==2759== by 0x406F27: boost::detail::thread_data_base::thread_data_base() (thread_data.hpp:54) ==2759== by 0x40BF1C: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;::thread_data(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;) (thread.hpp:48) ==2759== by 0x40B7F1: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;* boost::detail::heap_new_impl&lt;boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;, boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;&gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;) (thread_heap_alloc.hpp:47) ==2759== by 0x40AA8B: boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;* boost::detail::heap_new&lt;boost::detail::thread_data&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;, boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;&amp;) (thread_heap_alloc.hpp:73) ==2759== by 0x40A1C0: boost::shared_ptr&lt;boost::detail::thread_data_base&gt; boost::thread::make_thread_info&lt;boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt; &gt;(boost::_bi::bind_t&lt;void, cTestRunner, boost::_bi::list1&lt;boost::_bi::value&lt;std::string&gt; &gt; &gt;) (thread.hpp:136) ==2759== by 0x4092E1: boost::thread::thread&lt;cTestRunner, std::string&gt;(cTestRunner, std::string) (thread.hpp:227) ==2759== by 0x407D28: void startThread&lt;cTestRunner&gt;(std::string const&amp;) (test.cpp:36) ==2759== by 0x405DDB: main (test.cpp:71) ==2759== ==2759== ==2759== For counts of detected and suppressed errors, rerun with: -v ==2759== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1956 from 80) </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3585 Trac 1.4.3 Mihail Strashun <m.strashun@…> Mon, 02 Nov 2009 17:43:58 GMT attachment set https://svn.boost.org/trac10/ticket/3585 https://svn.boost.org/trac10/ticket/3585 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test.cpp</span> </li> </ul> Ticket Mihail Strashun <m.strashun@…> Mon, 02 Nov 2009 17:45:03 GMT version changed https://svn.boost.org/trac10/ticket/3585#comment:1 https://svn.boost.org/trac10/ticket/3585#comment:1 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.40.0</span> → <span class="trac-field-new">Boost 1.39.0</span> </li> </ul> Ticket anonymous Tue, 20 Apr 2010 21:23:30 GMT <link>https://svn.boost.org/trac10/ticket/3585#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3585#comment:2</guid> <description> <p> This is still a problem in 1.42. Has it been determined whether this a bug, or a false positive? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 20 Apr 2010 21:25:49 GMT</pubDate> <title>version changed https://svn.boost.org/trac10/ticket/3585#comment:3 https://svn.boost.org/trac10/ticket/3585#comment:3 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.39.0</span> → <span class="trac-field-new">Boost 1.42.0</span> </li> </ul> Ticket bvanassche@… Sat, 05 Jun 2010 12:05:41 GMT cc set https://svn.boost.org/trac10/ticket/3585#comment:4 https://svn.boost.org/trac10/ticket/3585#comment:4 <ul> <li><strong>cc</strong> <span class="trac-author">bvanassche@…</span> added </li> </ul> <p> As far as I can see thread_data_base::current_cond is signaled by thread::interrupt() but is never waited upon. That kind of access pattern is safe. This also means that it is safe to remove the member variable thread_data_base::current_cond from the Boost thread library. </p> Ticket viboes Sun, 04 Dec 2011 17:00:21 GMT <link>https://svn.boost.org/trac10/ticket/3585#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3585#comment:5</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/3585#comment:4" title="Comment 4">bvanassche@…</a>: </p> <blockquote class="citation"> <p> As far as I can see thread_data_base::current_cond is signaled by thread::interrupt() but is never waited upon. That kind of access pattern is safe. This also means that it is safe to remove the member variable thread_data_base::current_cond from the Boost thread library. </p> </blockquote> <p> Not yet. Have you take a look at libs/thread/src? </p> <pre class="wiki">grep -rHn current_cond * src/pthread/thread.cpp:416: if(local_thread_info-&gt;current_cond) src/pthread/thread.cpp:419: BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info-&gt;current_cond)); </pre><pre class="wiki">416 if(local_thread_info-&gt;current_cond) 417 { 418 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info-&gt;cond_mutex); 419 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info-&gt;current_cond)); 420 } </pre> </description> <category>Ticket</category> </item> <item> <author>bvanassche@…</author> <pubDate>Mon, 05 Dec 2011 18:45:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3585#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3585#comment:6</guid> <description> <p> Do you realize that the above grep output supports my claim that it is safe to remove thread_data_base::current_cond ? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 11 Dec 2011 02:58:02 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3585#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3585#comment:7</guid> <description> <p> In boost/thread </p> <pre class="wiki">grep -rHn current_cond * | grep -v svn pthread/thread_data.hpp:60: pthread_cond_t* current_cond; pthread/thread_data.hpp:67: current_cond(0) pthread/thread_data.hpp:104: thread_info-&gt;current_cond=cond; pthread/thread_data.hpp:119: thread_info-&gt;current_cond=NULL; </pre><p> Note that in line 104 current_cond stores an external condition that comes from the interruption_checker. It is the user of this external condition that will do the wait, isn't it? </p> <pre class="wiki">grep -rHn interruption_checker * | grep -v svn pthread/condition_variable.hpp:53: detail::interruption_checker check_for_interruption(&amp;internal_mutex,&amp;cond); pthread/condition_variable.hpp:71: detail::interruption_checker check_for_interruption(&amp;internal_mutex,&amp;cond); pthread/condition_variable.hpp:135: detail::interruption_checker check_for_interruption(&amp;internal_mutex,&amp;cond); pthread/condition_variable.hpp:159: detail::interruption_checker check_for_interruption(&amp;internal_mutex,&amp;cond); </pre><p> So IMO the current_cond can not be removed. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 11 Dec 2011 02:58:42 GMT</pubDate> <title>cc, owner, status changed https://svn.boost.org/trac10/ticket/3585#comment:8 https://svn.boost.org/trac10/ticket/3585#comment:8 <ul> <li><strong>cc</strong> <span class="trac-author">viboes</span> added </li> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket viboes Sun, 11 Dec 2011 08:54:29 GMT type changed https://svn.boost.org/trac10/ticket/3585#comment:9 https://svn.boost.org/trac10/ticket/3585#comment:9 <ul> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Support Requests</span> </li> </ul> <p> Why the signaling thread needs to lock the associated mutex? </p> <p> Moved to support request until resolution clarified. </p> Ticket viboes Thu, 29 Dec 2011 12:35:31 GMT status, type changed; resolution set https://svn.boost.org/trac10/ticket/3585#comment:10 https://svn.boost.org/trac10/ticket/3585#comment:10 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>type</strong> <span class="trac-field-old">Support Requests</span> → <span class="trac-field-new">Bugs</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/3585#comment:9" title="Comment 9">viboes</a>: </p> <blockquote class="citation"> <p> Why the signaling thread needs to lock the associated mutex? </p> <p> Moved to support request until resolution clarified. </p> </blockquote> <p> BTW, local_thread_info-&gt;current_cond is protected already by local_thread_info-&gt;cond_mutex </p> <pre class="wiki"> boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info-&gt;cond_mutex); BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info-&gt;current_cond)); </pre><p> So, for me this is a false positive. </p> Ticket