Boost C++ Libraries: Ticket #13283: boost log crash during thread termination https://svn.boost.org/trac10/ticket/13283 <p> I'm using boost 1.64 on iOS and Android. Adding trivial log causes a crash during thread termination. </p> <p> Removing more and more code produces the follwing example code for reproducing the issue. In the default settings in XCode it randomly crashed. </p> <p> Enabling all memory related helper in the Scheme (memory guards, ...) helps because it crashes more reproducible and procudes better callstacks. </p> <p> My result of debugging is: </p> <ol><li>the first executed log line -&gt; creates a thread local storage object with the severity - this severity is stored in <em>severity_level_holder</em> which creates a thread local storage with an automatic deleter (<em>boost::this_thread::at_thread_exit(boost::bind(checked_deleter&lt; uintmax_t &gt;(), p));</em>) - saw this in <em>severity_level.cpp</em> </li><li>normal Code -&gt; logging works </li><li>thread terminates </li><li>the destructor of the <a class="missing wiki">TestClass</a> is called and adds a result to the internal promise -&gt; logging works </li><li>the automatic deleter is called and frees the memory block for the severity. </li><li>the <a class="missing wiki">TestClass</a> of the internal promise is destroyed -&gt; logging crashes because it tries to read the destroyed severity memory block. </li></ol><pre class="wiki">#include &lt;memory&gt; #ifndef BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_PROVIDES_FUTURE #endif #ifndef BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION #define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION #endif #include &lt;boost/thread/thread.hpp&gt; #include &lt;boost/thread/future.hpp&gt; #include &lt;boost/log/trivial.hpp&gt; class TestClass { public: TestClass(bool shouldSet) : shouldSet_(shouldSet) {} virtual ~TestClass() { if (shouldSet_) { BOOST_LOG_TRIVIAL(warning) &lt;&lt; "crashes here"; promise_.set_value(std::unique_ptr&lt;TestClass&gt;(new TestClass(false))); } } bool shouldSet_; boost::promise&lt;std::unique_ptr&lt;TestClass&gt;&gt; promise_; }; int main(int, char **) { #define N 1 auto wait_future = boost::async([](){ auto task = []() { for (int i=0;i&lt;1000;i++) { BOOST_LOG_TRIVIAL(warning) &lt;&lt; "Create event #" &lt;&lt; i; std::shared_ptr&lt;TestClass&gt; event = std::shared_ptr&lt;TestClass&gt;(new TestClass(false)); boost::future&lt;std::unique_ptr&lt;TestClass&gt;&gt; future = event-&gt;promise_.get_future(); future.then([i](boost::future&lt;std::unique_ptr&lt;TestClass&gt;&gt;){BOOST_LOG_TRIVIAL(warning) &lt;&lt; "event handled #" &lt;&lt; i; }); boost::async([event, i](){ event-&gt;promise_.set_value(std::unique_ptr&lt;TestClass&gt;(new TestClass(true))); BOOST_LOG_TRIVIAL(warning) &lt;&lt; "Destroy event #" &lt;&lt; i; }).wait(); } }; boost::future&lt;void&gt; f[N]; for(int j=0; j&lt;N; j++){ f[j] = boost::async(task); } for(int j=0; j&lt;N; j++){ f[j].wait(); } }); wait_future.wait_for(boost::chrono::seconds(10)); return 0; } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/13283 Trac 1.4.3 Marco Strohner Thu, 22 Mar 2018 13:19:04 GMT version changed https://svn.boost.org/trac10/ticket/13283#comment:1 https://svn.boost.org/trac10/ticket/13283#comment:1 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.64.0</span> → <span class="trac-field-new">Boost 1.66.0</span> </li> </ul> <p> I've tested it again with boost 1.66.0 and the behaviour is the same. I also tried to compile boost with <em>BOOST_LOG_USE_COMPILER_TLS</em> but the behaviour is still the same. </p> <p> My results after more debugging: </p> <ol><li>the logging core creates a <em>thread_data</em> object for the first log that is executed in a thread (core.cpp:open_record). This is triggered by the line <em>BOOST_LOG_TRIVIAL(warning) &lt;&lt; "Destroy event #" &lt;&lt; i;</em> </li><li>This created <em>thread_data</em> object ist added to the <em>tss_node</em> map for automatic cleanup after thread execution is finished. </li><li>After the thread execution is finished the <em>tls_destructor</em> is called (thread.cpp:thread_proxy). This <em>tls_destructor</em> destroys the in step 1 created <em>thread_data</em> object </li><li>When the method <em>thread_proxy</em> is finished the reference counter of the lambda parameter <em>event</em> is decreased and the destructor is called. </li><li>The destructor tries to log one line (BOOST_LOG_TRIVIAL(warning) &lt;&lt; "crashes here";). But the method <em>get_thread_data</em> still returns the already destroyed pointer to the <em>thread_data</em> object. </li></ol> Ticket Kohei Takahashi Thu, 22 Mar 2018 15:20:43 GMT component changed; owner set https://svn.boost.org/trac10/ticket/13283#comment:2 https://svn.boost.org/trac10/ticket/13283#comment:2 <ul> <li><strong>owner</strong> set to <span class="trac-author">Andrey Semashev</span> </li> <li><strong>component</strong> <span class="trac-field-old">None</span> → <span class="trac-field-new">log</span> </li> </ul> Ticket Andrey Semashev Thu, 22 Mar 2018 17:55:45 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/13283#comment:3 https://svn.boost.org/trac10/ticket/13283#comment:3 <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> <p> So the problem seems to be that the code attempts to write a log record after the thread-local data has been destroyed, am I correct? If so, I'm sorry, but this use case is not going to be supported. Like with global destructors on program termination, there's generally no way to make sure that a thread-local object is still alive while the thread terminates and attempting to log at this point will always be unreliable. My advice is to avoid this practice and finish logging before the thread terminates. </p> Ticket