Boost C++ Libraries: Ticket #6320: race condition in boost::filesystem::path leads to crash when used in multithreaded programs https://svn.boost.org/trac10/ticket/6320 <p> following app crashes on VC10 (Windows 7) (multibyte and Unicode builds) at point of creation of path (im working around the issue by doing dummy string to wstring conversion) [ </p> <blockquote> <p> wstring r; std::copy(s.begin(),s.end(),r.begin()); </p> </blockquote> <p> ] </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/thread.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/filesystem.hpp&gt;</span><span class="cp"></span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">sPath</span><span class="p">(</span><span class="s">&quot;c:</span><span class="se">\\</span><span class="s">Development&quot;</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">thread_group</span> <span class="n">tg</span><span class="p">;</span> <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">tg</span><span class="p">.</span><span class="n">create_thread</span><span class="p">([</span><span class="o">&amp;</span><span class="n">sPath</span><span class="p">](){</span> <span class="n">boost</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">10</span><span class="p">));</span> <span class="n">boost</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">p</span><span class="p">(</span><span class="n">sPath</span><span class="p">);</span> <span class="n">boost</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span> <span class="n">di</span><span class="p">(</span><span class="n">p</span><span class="p">),</span> <span class="n">end</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span><span class="n">di</span> <span class="o">!=</span> <span class="n">end</span><span class="p">)</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">di</span><span class="o">++</span><span class="p">)).</span><span class="n">path</span><span class="p">().</span><span class="n">string</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="p">});</span> <span class="p">}</span> <span class="n">tg</span><span class="p">.</span><span class="n">join_all</span><span class="p">();</span> <span class="kt">int</span> <span class="n">a</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">a</span><span class="p">;</span> <span class="p">}</span> </pre></div></div><p> VC10 <a class="missing wiki">CallStack</a>: </p> <pre class="wiki">&gt; msvcp100d.dll!std::codecvt&lt;wchar_t,char,int&gt;::in(int &amp; _State, const char * _First1, const char * _Last1, const char * &amp; _Mid1, wchar_t * _First2, wchar_t * _Last2, wchar_t * &amp; _Mid2) Line 1521 + 0x1f bytes C++ filesystem_crash.exe!`anonymous namespace'::convert_aux(const char * from, const char * from_end, wchar_t * to, wchar_t * to_end, std::basic_string&lt;wchar_t,std::char_traits&lt;wchar_t&gt;,std::allocator&lt;wchar_t&gt; &gt; &amp; target, const std::codecvt&lt;wchar_t,char,int&gt; &amp; cvt) Line 84 + 0x25 bytes C++ filesystem_crash.exe!boost::filesystem3::path_traits::convert(const char * from, const char * from_end, std::basic_string&lt;wchar_t,std::char_traits&lt;wchar_t&gt;,std::allocator&lt;wchar_t&gt; &gt; &amp; to, const std::codecvt&lt;wchar_t,char,int&gt; &amp; cvt) Line 165 + 0x20 bytes C++ filesystem_crash.exe!boost::filesystem3::path_traits::dispatch&lt;std::basic_string&lt;wchar_t,std::char_traits&lt;wchar_t&gt;,std::allocator&lt;wchar_t&gt; &gt; &gt;(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; c, std::basic_string&lt;wchar_t,std::char_traits&lt;wchar_t&gt;,std::allocator&lt;wchar_t&gt; &gt; &amp; to, const std::codecvt&lt;wchar_t,char,int&gt; &amp; cvt) Line 174 + 0x7e bytes C++ filesystem_crash.exe!boost::filesystem3::path::path&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &gt;(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; source, void * __formal) Line 135 + 0x13 bytes C++ filesystem_crash.exe!`anonymous namespace'::&lt;lambda0&gt;::operator()() Line 15 + 0x10 bytes C++ filesystem_crash.exe!boost::detail::thread_data&lt;`anonymous namespace'::&lt;lambda0&gt; &gt;::run() Line 62 C++ filesystem_crash.exe!boost::`anonymous namespace'::thread_start_function(void * param) Line 177 C++ msvcr100d.dll!_callthreadstartex() Line 314 + 0xf bytes C msvcr100d.dll!_threadstartex(void * ptd) Line 297 C </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/6320 Trac 1.4.3 wolfgang.fertsak@… Tue, 27 Dec 2011 16:05:14 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:1</guid> <description> <p> I think the problem is in file filesystem/v3/source/path.cpp in method </p> <blockquote> <p> const path::codecvt_type *&amp; path::wchar_t_codecvt_facet() { </p> <blockquote> <p> static const std::codecvt&lt;wchar_t, char, std::mbstate_t&gt; * </p> <blockquote> <p> facet( </p> <blockquote> <p> &amp;std::use_facet&lt;std::codecvt&lt;wchar_t, char, std::mbstate_t&gt; &gt; </p> <blockquote> <p> (path_locale())); </p> </blockquote> </blockquote> </blockquote> <p> return facet; </p> </blockquote> <p> } </p> </blockquote> <p> This method is entered by multiple threads concurrently and the static pointer "facet" gets initialized by the first thread (which takes some time) but the other threads don't wait and just continue while facet is a NULL pointer. </p> <p> In boost 1.44 this crash didn't occur. It seems that the initialization of global variable const fs::path dot_path(L"."); in filesystem/v3/source/path.cpp resulted in a call of path::wchar_t_codecvt_facet(), so the static "facet" pointer got initialized during program startup while no other threads were running. </p> <p> In boost 1.48 the initialization of the same globale variable doesn't result in a call of path::wchar_t_codecvt_facet() so race conditions might occur during initialization of the static "facet" pointer (in C++ 03). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Beman Dawes</dc:creator> <pubDate>Wed, 04 Jan 2012 14:53:51 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/6320#comment:2 https://svn.boost.org/trac10/ticket/6320#comment:2 <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> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/76303" title="Fix #4889, #6320, Locale codecvt_facet not thread safe on Windows. ...">[76303]</a>) Fix <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4889" title="#4889: Bugs: path locale-related functions are not thread-safe (closed: fixed)">#4889</a>, <a class="reopened ticket" href="https://svn.boost.org/trac10/ticket/6320" title="#6320: Bugs: race condition in boost::filesystem::path leads to crash when used in ... (reopened)">#6320</a>, Locale codecvt_facet not thread safe on Windows. Move Windows, Mac OS X, locale and codecvt facet back to namespace scope. POSIX except OS X uses local static initialization (IE lazy) to ensure exceptions are catchable if environmental variables are misconfigured and to avoid use of locale("") if not actually used. </p> Ticket anonymous Wed, 31 Oct 2012 09:01:52 GMT status, version, severity changed; resolution deleted https://svn.boost.org/trac10/ticket/6320#comment:3 https://svn.boost.org/trac10/ticket/6320#comment:3 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>version</strong> <span class="trac-field-old">Boost 1.48.0</span> → <span class="trac-field-new">Boost 1.51.0</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">fixed</span> </li> <li><strong>severity</strong> <span class="trac-field-old">Showstopper</span> → <span class="trac-field-new">Problem</span> </li> </ul> <p> This issue still appears to be present, using: </p> <p> MSVC 2012 (Win7, 32-bit). <strong>Statically</strong> linked to boost::filesystem. </p> <p> Just modified the example code to use "C:/" as the directory search path (to ensure existence). </p> <p> Code asserts in .../libs/filesystem/src/path.cpp, line 888: </p> <pre class="wiki">#if defined(BOOST_WINDOWS_API) &amp;&amp; defined(BOOST_FILESYSTEM_STATIC_LINK) const path::codecvt_type&amp; path::codecvt() { BOOST_ASSERT_MSG(codecvt_facet_ptr(), "codecvt_facet_ptr() facet hasn't been properly initialized"); return *codecvt_facet_ptr(); } </pre> Ticket jacob.schloss@… Fri, 14 Dec 2012 18:38:15 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:4</guid> <description> <p> I agree the issue is still present, I am getting crashes due to invalid access inside the path conversion routines. As original poster says issue is that the initialization of static members is not threadsafe in all pre c++11 compilers. This seems to be compiler dependent, gcc seems to default to adding serialization code, but provides -fno-threadsafe-statics to disable, <a class="ext-link" href="http://stackoverflow.com/questions/10585928/is-static-init-thread-safe-with-vc2010"><span class="icon">​</span>MSVC seems to not be</a>. I am currently using MSVC 2010. </p> <p> Although this comment states that the local is thread local </p> <pre class="wiki">// The path locale, which is global to the thread, can be changed by the // imbue() function. It is initialized to an implementation defined locale. </pre><p> It looks like the same path object is shared between threads </p> <pre class="wiki"> std::locale&amp; path_locale() { static std::locale loc(default_locale()); return loc; } </pre><p> Adding explicit one time initialization code to the shared local object with boost::call_once works for me. </p> <pre class="wiki"> void make_loc(std::locale&amp; loc) { loc = default_locale(); } std::locale&amp; path_locale() { static std::locale loc; static boost::once_flag once; boost::call_once(once, boost::bind(&amp;make_loc, boost::ref(loc))); return loc; } </pre><pre class="wiki"> void make_wchar_t_codecvt_facet(const path::codecvt_type *&amp; cvt) { cvt = &amp;std::use_facet&lt;std::codecvt&lt;wchar_t, char, std::mbstate_t&gt; &gt; (path_locale()); } const path::codecvt_type *&amp; path::wchar_t_codecvt_facet() { static const std::codecvt&lt;wchar_t, char, std::mbstate_t&gt; * facet; static boost::once_flag once; boost::call_once(once, boost::bind(&amp;make_wchar_t_codecvt_facet, boost::ref(facet))); return facet; } </pre><p> Another workaround that seemed to work is to do a path string operation on one thread in advance of multithread operations. </p> </description> <category>Ticket</category> </item> <item> <author>jacob.schloss@…</author> <pubDate>Sat, 22 Dec 2012 00:31:59 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:5</guid> <description> <p> The call once struct should probably also not be static, I should pull those out. </p> </description> <category>Ticket</category> </item> <item> <author>jacob.schloss@…</author> <pubDate>Sat, 22 Dec 2012 00:33:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:6</guid> <description> <p> Turning on /we4640 to make these warnings errors produces a large number of hits, there are other places where const static "empty path" objects are local to functions. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Beman Dawes</dc:creator> <pubDate>Fri, 22 Feb 2013 13:35:41 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/6320#comment:7 https://svn.boost.org/trac10/ticket/6320#comment:7 <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> Boost.Filesystem's implementation of path locale and codecvt handling has been rewritten with much simpler, more portable, and hopefully more robust code. The interface has not changed. The rewrite has been applied to svn trunk as of revision 83062. An added reference documentation section (boost-root/libs/filesystem/doc/reference.html#path-Usage) describes class path usage concerns, such as thread data races. </p> <p> These changes should resolve this issue. If you believe it has not been resolved satisfactorily, please open a new issue rather than reopening this issue. But before you do that, please read boost-root/libs/filesystem/doc/reference.html#path-Usage to be sure that the problem you are seeing is not a manifestation of one of the those concerns. If you do open a new issue, please be specific and supply a test case and lots of details. Just saying something "doesn't work" or "crashes" is not enough! </p> <p> Thanks, </p> <p> --Beman </p> Ticket alexey.meteorite@… Fri, 17 May 2013 13:03:27 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:8</guid> <description> <p> I used revision 83062 and it still crashed because of race condition in codecvt(). Call to codecvt() resulted from my call to fs::exists. I used VC9 and static linking.<br /> I uncommented locale_mutex and its locks in codecvt() and imbue(const std::locale&amp; loc), now everything is fine. </p> <p> So, please, include mutex into next boost release. Or at least provide some build variant with it, that can be turned on. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Vadim Panin</dc:creator> <pubDate>Fri, 23 Aug 2013 15:10:44 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:9</guid> <description> <p> Have not found "boost-root/libs/filesystem/doc/reference.html#path-Usage" section you are referring to. The following workaround works for me: </p> <pre class="wiki">#ifdef _MSC_VER // fix for https://svn.boost.org/trac/boost/ticket/6320 boost::filesystem::path::imbue( std::locale( "" ) ); #endif </pre><p> if placed in main(). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 11 Oct 2013 11:52:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:10</guid> <description> <p> If you're using Boost as a static lib in a DLL you have to apply the fix in the DLLMain example: </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#ifdef WIN32</span> <span class="cp">#ifndef WIN32_LEAN_AND_MEAN</span> <span class="cp">#define WIN32_LEAN_AND_MEAN</span> <span class="cp">#endif</span> <span class="cp">#include</span> <span class="cpf">&lt;Windows.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/filesystem/path.hpp&gt;</span><span class="cp"></span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">init_boost</span> <span class="p">()</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">p</span><span class="p">(</span><span class="s">&quot;dummy&quot;</span><span class="p">);</span> <span class="p">};</span> <span class="n">BOOL</span> <span class="n">APIENTRY</span> <span class="nf">DllMain</span><span class="p">(</span> <span class="n">HMODULE</span> <span class="cm">/* hModule */</span><span class="p">,</span> <span class="n">DWORD</span> <span class="n">ul_reason_for_call</span><span class="p">,</span> <span class="n">LPVOID</span> <span class="cm">/* lpReserved */</span><span class="p">)</span> <span class="p">{</span> <span class="k">switch</span> <span class="p">(</span><span class="n">ul_reason_for_call</span><span class="p">)</span> <span class="p">{</span> <span class="k">case</span> <span class="nl">DLL_PROCESS_ATTACH</span><span class="p">:</span> <span class="n">init_boost</span><span class="p">();</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="nl">DLL_THREAD_ATTACH</span><span class="p">:</span> <span class="k">case</span> <span class="nl">DLL_THREAD_DETACH</span><span class="p">:</span> <span class="k">case</span> <span class="nl">DLL_PROCESS_DETACH</span><span class="p">:</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">TRUE</span><span class="p">;</span> <span class="p">}</span> <span class="cp">#endif</span> </pre></div></div> </description> <category>Ticket</category> </item> <item> <author>dwieselwind@…</author> <pubDate>Wed, 11 Jun 2014 05:31:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:11</guid> <description> <p> I'm experiencing this too on 1.55 and MSVC10. Vadim Panin's hack works fine for me. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Wed, 03 Dec 2014 12:26:35 GMT</pubDate> <title>status changed; resolution deleted https://svn.boost.org/trac10/ticket/6320#comment:12 https://svn.boost.org/trac10/ticket/6320#comment:12 <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">fixed</span> </li> </ul> Ticket anonymous Wed, 03 Dec 2014 12:28:14 GMT version changed https://svn.boost.org/trac10/ticket/6320#comment:13 https://svn.boost.org/trac10/ticket/6320#comment:13 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.51.0</span> → <span class="trac-field-new">Boost 1.52.0</span> </li> </ul> Ticket anonymous Tue, 31 Mar 2015 12:49:05 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:14</guid> <description> <p> Do not something in <a class="missing wiki">DllMain</a>. </p> <p> When called DLL_PROCESS_ATTACH/DLL_PROCESS_DETACH system is inoperative. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Sun, 20 Mar 2016 22:50:10 GMT</pubDate> <title>version changed https://svn.boost.org/trac10/ticket/6320#comment:15 https://svn.boost.org/trac10/ticket/6320#comment:15 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.52.0</span> → <span class="trac-field-new">Boost 1.60.0</span> </li> </ul> Ticket raad@… Mon, 27 Jun 2016 13:08:35 GMT cc set https://svn.boost.org/trac10/ticket/6320#comment:16 https://svn.boost.org/trac10/ticket/6320#comment:16 <ul> <li><strong>cc</strong> <span class="trac-author">raad@…</span> added </li> </ul> Ticket anonymous Sat, 17 Sep 2016 00:13:08 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:17</guid> <description> <p> Experiencing this on 1.61.0 too. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Sat, 17 Sep 2016 04:18:07 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:18 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:18</guid> <description> <p> 1.61.0 MSVC120 </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 30 Sep 2016 12:43:13 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:19 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:19</guid> <description> <p> I exeperience the same issue with 1.60.0 with VS2010 </p> </description> <category>Ticket</category> </item> <item> <dc:creator>stl</dc:creator> <pubDate>Mon, 07 Nov 2016 16:57:26 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:20 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:20</guid> <description> <p> Just had 1.61.0 crash due to this issue and investigated a bit. The root of the problem is the initialization of a local static inside path_locale(). </p> <p> See path.cpp line 925: </p> <pre class="wiki">static std::locale loc(default_locale()); </pre><p> This obviously leads to a race between threads with compilers that do not implement thread-safe initialization of local statics. BTW, none of the MSVC compilers before VC2015 do implement this feature, which Microsoft likes to call "magic statics". </p> <p> So I did some tests with Visual Studio 2015 Update 3. I tested with the default v140 toolset and with the XP-compatibility toolset v140_xp. Here are the rather interesting results: </p> <p> v140 toolset: works fine. v140_xp toolset: race, crash and burn. </p> <p> If you step through the code compiled with v140, you can see the thread sync stubs that are automatically inserted by v140. Step through the same code compiled with v140_xp -&gt; no thread sync stubs. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>stl</dc:creator> <pubDate>Tue, 08 Nov 2016 17:40:03 GMT</pubDate> <title>version changed https://svn.boost.org/trac10/ticket/6320#comment:21 https://svn.boost.org/trac10/ticket/6320#comment:21 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.60.0</span> → <span class="trac-field-new">Boost 1.62.0</span> </li> </ul> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/6320#comment:20" title="Comment 20">stl</a>: </p> <blockquote class="citation"> <p> v140 toolset: works fine.<br /> v140_xp toolset: race, crash and burn.<br /> </p> </blockquote> <p> <strong>Clarification:</strong> the above mentioned toolsets can be selected in VS 2015 C++ project settings, and are not to be confused with the bjam "toolset" parameter. In the above tests I used a special build of boost built with the VS2015 v140_xp toolset. You cannot normally do this with unmodified boost.build scripts. </p> <p> However, Windows XP woes aside, the boost download page clearly states for the Visual C++ compilers that the following compilers are supported: </p> <p> Visual C++: 7.1, 8.0, 9.0, 10.0, 11.0, 12.0, 14.0 </p> <p> This bug is still present in the latest boost v1.62.0 release, and leads to crashes with all of the above compilers up to 12.0, and even with 14.0 when using the command line switch "/Zc:threadSafeInit-" which disables thread-safe initialization of scoped statics [and is the default with v140_xp toolset for DLLs using ATL]. </p> Ticket stl Tue, 08 Nov 2016 17:43:11 GMT severity, summary changed https://svn.boost.org/trac10/ticket/6320#comment:22 https://svn.boost.org/trac10/ticket/6320#comment:22 <ul> <li><strong>severity</strong> <span class="trac-field-old">Problem</span> → <span class="trac-field-new">Showstopper</span> </li> <li><strong>summary</strong> <span class="trac-field-old">creation of path from std::string on Windows (VC10) crashes (access error)</span> → <span class="trac-field-new">race condition in boost::filesystem::path leads to crash when used in multithreaded programs</span> </li> </ul> Ticket stl Tue, 08 Nov 2016 17:56:23 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:23 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:23</guid> <description> <p> Some simplified code to reproduce the crash. As concurrency bugs are timing dependent, this will crash most of the time, but not always. </p> <pre class="wiki">#include &lt;boost/filesystem.hpp&gt; #include &lt;boost/thread.hpp&gt; void thr() { boost::filesystem::path file(L"C:\\test"); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); std::cout &lt;&lt; file.string() &lt;&lt; std::endl; } int main() { boost::thread_group tg; for (size_t n = 0; n &lt; 5; ++n) { tg.create_thread(thr); } tg.join_all(); return 0; } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>stl</dc:creator> <pubDate>Tue, 08 Nov 2016 18:09:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:24 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:24</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/6320#comment:23" title="Comment 23">stl</a>: </p> <blockquote class="citation"> <p> Some simplified code to reproduce the crash. As concurrency bugs are timing dependent, this will crash most of the time, but not always. </p> <pre class="wiki">#include &lt;boost/filesystem.hpp&gt; #include &lt;boost/thread.hpp&gt; void thr() { boost::filesystem::path file(L"C:\\test"); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); std::cout &lt;&lt; file.string() &lt;&lt; std::endl; } int main() { boost::thread_group tg; for (size_t n = 0; n &lt; 5; ++n) { tg.create_thread(thr); } tg.join_all(); return 0; } </pre></blockquote> <p> Of course, this code is meant to reproduce the crash on Windows, where boost::filesystem::path uses wide characters natively, and thus must convert when using string(). </p> </description> <category>Ticket</category> </item> <item> <author>valentin.kotolup@…</author> <pubDate>Thu, 17 Nov 2016 20:21:43 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:25 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:25</guid> <description> <p> BOOST 1.61.0. MSVC 12 Update 4 </p> <pre class="wiki">std::string some_path("C:\\something"); boost::filesystem::file_size(some_path); </pre><p> Workaround from Vadim Panin works. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 09 May 2017 15:07:24 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:26 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:26</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/6320#comment:24" title="Comment 24">stl</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/6320#comment:23" title="Comment 23">stl</a>: </p> <blockquote class="citation"> <p> Some simplified code to reproduce the crash. As concurrency bugs are timing dependent, this will crash most of the time, but not always. </p> <pre class="wiki">#include &lt;boost/filesystem.hpp&gt; #include &lt;boost/thread.hpp&gt; void thr() { boost::filesystem::path file(L"C:\\test"); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); std::cout &lt;&lt; file.string() &lt;&lt; std::endl; } int main() { boost::thread_group tg; for (size_t n = 0; n &lt; 5; ++n) { tg.create_thread(thr); } tg.join_all(); return 0; } </pre></blockquote> <p> Of course, this code is meant to reproduce the crash on Windows, where boost::filesystem::path uses wide characters natively, and thus must convert when using string(). </p> </blockquote> <p> <code>boost::barrier</code> can help a lot to catch threading issues: </p> <pre class="wiki">const int num = 10; boost::barrier b(num + 1); std::vector&lt;std::thread&gt; threads; for (int i = 0; i &lt; num; ++i) threads.emplace_back([&amp;b] { b.wait(); boost::filesystem::path::codecvt(); }); b.wait(); for (auto&amp; thread: threads) thread.join(); </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 09 May 2017 16:07:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:27 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:27</guid> <description> <p> I've got a suggestion to resolve the issue. </p> <p> I think we should rewrite <code>std::locale&amp; path_locale()</code> in the unnamed namespace in path.cpp </p> <p> Instead of using <code>static std::locale</code> (the original code): </p> <pre class="wiki">std::locale&amp; path_locale() { static std::locale loc(default_locale()); return loc; } </pre><p> in pre-c++11 we could use an atomic pointer: </p> <pre class="wiki">std::mutex&amp; locale_mutex() { static std::mutex mutex; return mutex; } std::unique_ptr&lt;std::locale&gt;&amp; locale_unique_ptr() { static std::unique_ptr&lt;std::locale&gt; locale; return locale; } std::atomic&lt;std::locale*&gt;&amp; locale_pointer() { static std::atomic&lt;std::locale*&gt; locale; return locale; } std::locale&amp; path_locale() { if (!locale_pointer().load()) { std::lock_guard&lt;std::mutex&gt; l(locale_mutex()); if (!locale_pointer().load()) { locale_unique_ptr() = std::make_unique&lt;std::locale&gt;(default_locale()); locale_pointer().store(locale_unique_ptr().get()); } } return *locale_pointer().load(); } </pre><p> In the path.hpp we could add a dummy static object (int) to initialise the mutex, the unique_ptr and the atomic ptr. </p> <pre class="wiki">namespace { int dummy = boost::filesystem::path::codecvt_init(); } </pre><p> This static dummy goes to every compilation unit where boost/path.hpp is included and causes the initilisation of the necessary local static helper objects (mutex, atomic and unique ptrs). </p> <p> <code>codecvt_init()</code> is a static member of the path class and it is defined in the end of the path.cpp file (where path::codecvt is defined, too): </p> <pre class="wiki">int boost::filesystem::path::codecvt_init() { locale_mutex(); locale_pointer(); locale_unique_ptr(); return 0; } </pre><p> If our program never calls <code>path::codecvt</code> the unique ptr remains empty (but initialised!) so it is up the the client when the locale (and the facet) initialisation happens. This is important because on POSIX platforms it can result an exception to be thrown so we do not want to do the initialisation until the <code>main</code> is called. (Please note this is not always possible, e.g. there is a static logger class instance that uses <code>path::codecvt</code> before the <code>main</code> is reached.) </p> <p> Only bit I do not like (have not been able to sort out) that the path class public interface would have a new static function (<code>codecvt_init</code>). Calling it by the clients would not cause any harm, but it would be better to hide it somehow. I do not think this the end of the world. Eliminating the crash, i guess, is more important than paying a little price in the form of polluting the interface with a dummy function. </p> <p> I used <code>std::atomic</code>, <code>std::uinique_ptr</code>, <code>std::mutex</code> and <code>std::lock_guard</code> that have to be replaced with the corresponding boost classes. It is also neccessary to add an #if &lt;pre c++11&gt; ... #else ... #endif preprocessor condition to switch between the proposed or the original code. </p> <p> I wonder whether this would be less efficient than the local static stuff. </p> <ol><li>Not if we use c++11 (the preprocessor condition would switch) </li><li>I guess, even the local static magic implementation needs some kind of synchronisation for initialisation/access local static objects that may not be less costly than that the atomic ptr version demands </li></ol><p> I would be grateful if someone could comment on the idea. If you think it's worth considering it as a solution I could work on patch for review. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 09 May 2017 16:28:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:28 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:28</guid> <description> <p> Just noticed that one load could be spared: </p> <pre class="wiki">std::locale&amp; path_locale() { std::locale* locale = nullptr; if (!(locale = locale_pointer().load())) { std::lock_guard&lt;std::mutex&gt; l(locale_mutex()); if (!(locale = locale_pointer().load())) { locale_unique_ptr() = std::make_unique&lt;std::locale&gt;(default_locale()); locale_pointer().store(locale = locale_unique_ptr().get()); } } return *locale; } </pre> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Tue, 09 May 2017 18:56:03 GMT</pubDate> <title>cc changed https://svn.boost.org/trac10/ticket/6320#comment:29 https://svn.boost.org/trac10/ticket/6320#comment:29 <ul> <li><strong>cc</strong> <span class="trac-author">daniel.kruegler@…</span> added </li> </ul> Ticket anonymous Tue, 08 Aug 2017 10:37:30 GMT version changed https://svn.boost.org/trac10/ticket/6320#comment:30 https://svn.boost.org/trac10/ticket/6320#comment:30 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.62.0</span> → <span class="trac-field-new">Boost 1.64.0</span> </li> </ul> <p> With 1.64 it is still there. Has it some priority? Or it will be gone with static inicializing thread-safe compilers (I use MSVC 2013, which is probably not)? </p> <pre class="wiki">Unhandled exception thrown: read access violation. _Loc._Ptr was nullptr. </pre><p> Incriminated thread (optimized code): </p> <pre class="wiki"> [Inline Frame] My.dll!std::locale::_Getfacet(unsigned __int64) Line 468 My.dll!std::use_facet&lt;std::codecvt&lt;wchar_t,char,int&gt; &gt;(const std::locale &amp; _Loc) Line 572 My.dll!MyCode() Line 692 // calling boost::filesystem::path(const std::string &amp;) </pre><p> I also suspect path_locale(), where is static inicializing global shared object across threads. </p> Ticket sali98@… Fri, 11 Aug 2017 21:36:33 GMT <link>https://svn.boost.org/trac10/ticket/6320#comment:31 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:31</guid> <description> <p> Kind of curious, why this one is not fixed until now? We have found a few crash reports related to this bug. </p> <p> Maybe we have to upgrade from vs2013 to vs2015? Unfortunately, our code base is not ready for that yet:-( </p> </description> <category>Ticket</category> </item> <item> <author>eksea@…</author> <pubDate>Tue, 21 Nov 2017 03:07:22 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:32 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:32</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/6320#comment:27" title="Comment 27">匿名用户</a>: </p> <blockquote class="citation"> <p> I've got a suggestion to resolve the issue. </p> <p> I think we should rewrite <code>std::locale&amp; path_locale()</code> in the unnamed namespace in path.cpp </p> <p> Instead of using <code>static std::locale</code> (the original code): </p> <pre class="wiki">std::locale&amp; path_locale() { static std::locale loc(default_locale()); return loc; } </pre><p> in pre-c++11 we could use an atomic pointer: </p> <pre class="wiki">std::mutex&amp; locale_mutex() { static std::mutex mutex; return mutex; } std::unique_ptr&lt;std::locale&gt;&amp; locale_unique_ptr() { static std::unique_ptr&lt;std::locale&gt; locale; return locale; } std::atomic&lt;std::locale*&gt;&amp; locale_pointer() { static std::atomic&lt;std::locale*&gt; locale; return locale; } std::locale&amp; path_locale() { if (!locale_pointer().load()) { std::lock_guard&lt;std::mutex&gt; l(locale_mutex()); if (!locale_pointer().load()) { locale_unique_ptr() = std::make_unique&lt;std::locale&gt;(default_locale()); locale_pointer().store(locale_unique_ptr().get()); } } return *locale_pointer().load(); } </pre><p> In the path.hpp we could add a dummy static object (int) to initialise the mutex, the unique_ptr and the atomic ptr. </p> <pre class="wiki">namespace { int dummy = boost::filesystem::path::codecvt_init(); } </pre><p> This static dummy goes to every compilation unit where boost/path.hpp is included and causes the initilisation of the necessary local static helper objects (mutex, atomic and unique ptrs). </p> <p> <code>codecvt_init()</code> is a static member of the path class and it is defined in the end of the path.cpp file (where path::codecvt is defined, too): </p> <pre class="wiki">int boost::filesystem::path::codecvt_init() { locale_mutex(); locale_pointer(); locale_unique_ptr(); return 0; } </pre><p> If our program never calls <code>path::codecvt</code> the unique ptr remains empty (but initialised!) so it is up the the client when the locale (and the facet) initialisation happens. This is important because on POSIX platforms it can result an exception to be thrown so we do not want to do the initialisation until the <code>main</code> is called. (Please note this is not always possible, e.g. there is a static logger class instance that uses <code>path::codecvt</code> before the <code>main</code> is reached.) </p> <p> Only bit I do not like (have not been able to sort out) that the path class public interface would have a new static function (<code>codecvt_init</code>). Calling it by the clients would not cause any harm, but it would be better to hide it somehow. I do not think this the end of the world. Eliminating the crash, i guess, is more important than paying a little price in the form of polluting the interface with a dummy function. </p> <p> I used <code>std::atomic</code>, <code>std::uinique_ptr</code>, <code>std::mutex</code> and <code>std::lock_guard</code> that have to be replaced with the corresponding boost classes. It is also neccessary to add an #if &lt;pre c++11&gt; ... #else ... #endif preprocessor condition to switch between the proposed or the original code. </p> <p> I wonder whether this would be less efficient than the local static stuff. </p> <ol><li>Not if we use c++11 (the preprocessor condition would switch) </li><li>I guess, even the local static magic implementation needs some kind of synchronisation for initialisation/access local static objects that may not be less costly than that the atomic ptr version demands </li></ol><p> I would be grateful if someone could comment on the idea. If you think it's worth considering it as a solution I could work on patch for review. </p> </blockquote> <p> This workaround works for me. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 23 Feb 2018 02:16:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:33 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:33</guid> <description> <p> I am working with 1.66 on windows and experiencing the issue. Has there been focus on this to address it? </p> </description> <category>Ticket</category> </item> <item> <author>alexandre.nunes@…</author> <pubDate>Tue, 20 Mar 2018 00:10:50 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:34 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:34</guid> <description> <p> I'm hit by this too. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Sun, 22 Apr 2018 11:42:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6320#comment:35 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6320#comment:35</guid> <description> <p> I've also encountered this issue. </p> </description> <category>Ticket</category> </item> </channel> </rss>