Boost C++ Libraries: Ticket #12987: boost::filesystem::exists crashes https://svn.boost.org/trac10/ticket/12987 <pre class="wiki">bool dummy = boost::filesystem::exists("C:\\alma.txt"); //1 class Alma { public: ~Alma() { std::cout &lt;&lt; boost::filesystem::path("c:\\alma.txt").string() &lt;&lt; std::endl; } }; Alma a; //2 int main(int argc, char* argv[]) { Alma(); //3 return 0; } </pre><p> The reason for the crash is that "dummy" is initialised before "equal_string_ordinal_ic" in the unnamed namespace in operations.cpp. The fix (or a possible fix) is easy. I made operations.cpp a bit uglier by moving static stuff to "perms make_permissions(const path&amp;, DWORD)": </p> <pre class="wiki">perms make_permissions(const path&amp; p, DWORD attr) { //this was in the unnamed namespace: static PtrRtlEqualUnicodeString rtl_equal_unicode_string_api = PtrRtlEqualUnicodeString( ::GetProcAddress( ::GetModuleHandleW(L"ntdll.dll"), "RtlEqualUnicodeString")); //this was in the unnamed namespace: static bool(*equal_string_ordinal_ic)(const wchar_t*, const wchar_t*, PtrRtlEqualUnicodeString) = rtl_equal_unicode_string_api ? equal_string_ordinal_ic_1 : equal_string_ordinal_ic_2; perms prms = fs::owner_read | fs::group_read | fs::others_read; if ((attr &amp; FILE_ATTRIBUTE_READONLY) == 0) prms |= fs::owner_write | fs::group_write | fs::others_write; path ext = p.extension(); if (equal_string_ordinal_ic(ext.c_str(), L".exe", rtl_equal_unicode_string_api) || equal_string_ordinal_ic(ext.c_str(), L".com", rtl_equal_unicode_string_api) || equal_string_ordinal_ic(ext.c_str(), L".bat", rtl_equal_unicode_string_api) || equal_string_ordinal_ic(ext.c_str(), L".cmd", rtl_equal_unicode_string_api)) prms |= fs::owner_exe | fs::group_exe | fs::others_exe; return prms; } </pre><p> I also changed the signatures of two locally used functions: </p> <pre class="wiki">bool equal_string_ordinal_ic_1(const wchar_t* s1, const wchar_t* s2, PtrRtlEqualUnicodeString rtl_equal_unicode_string_api) bool equal_string_ordinal_ic_2(const wchar_t* s1, const wchar_t* s2, PtrRtlEqualUnicodeString) </pre><p> And now that the static stuff is moved from the unnamed namespace to the make_permissions method there is no crash anymore. </p> <p> At least until I comment out (<em>1). Please note that (</em>3) is needed for the second type of crash. This second type of crash is not entirely new. There is a bug filed 5 years ago. I think someone who is involved in developing boost::filesystem with this info (that the second type of crash does not occur if we call (<em>1) (supposed make_permissions has been fixed)) could sort out that old bug as well. <a class="ext-link" href="https://svn.boost.org/trac/boost/ticket/6638"><span class="icon">​</span>https://svn.boost.org/trac/boost/ticket/6638</a> </em></p> <p> This static initialisation/destruction looks a nasty business. </p> <p> compiler: vc14, static lib, statically linked runtime </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12987 Trac 1.4.3 anonymous Tue, 25 Apr 2017 00:24:50 GMT <link>https://svn.boost.org/trac10/ticket/12987#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:1</guid> <description> <p> I encountered the same problem using vc2010 on win10. </p> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Wed, 26 Apr 2017 05:46:56 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:2</guid> <description> <p> I will work on a solution. We also need to ensure that static local function initialization is thread-safe, which is not meet before VS 2017, therefore your suggested workaround has some limitations. </p> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Wed, 26 Apr 2017 05:58:54 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:3</guid> <description> <p> Correction: I meant VS 2013 instead of VS 2017 in regard to thread-safe function statics. </p> </description> <category>Ticket</category> </item> <item> <author>mika.fischer@…</author> <pubDate>Wed, 26 Apr 2017 10:50:14 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/12987#comment:4 https://svn.boost.org/trac10/ticket/12987#comment:4 <ul> <li><strong>cc</strong> <span class="trac-author">mika.fischer@…</span> added </li> </ul> Ticket Leinad Wed, 26 Apr 2017 16:31:35 GMT <link>https://svn.boost.org/trac10/ticket/12987#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:5</guid> <description> <p> Yes that's correct. I think it's a c++11 feature, but we use this already in path.cpp: </p> <pre class="wiki"> std::locale&amp; path_locale() // std::locale("") construction, needed on non-Apple POSIX systems, can throw // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so // path_locale() provides lazy initialization via a local static to ensure that any // exceptions occur after main() starts and so can be caught. Furthermore, // path_locale() is only called if path::codecvt() or path::imbue() are themselves // actually called, ensuring that an exception will only be thrown if std::locale("") // is really needed. { // [locale] paragraph 6: Once a facet reference is obtained from a locale object by // calling use_facet&lt;&gt;, that reference remains usable, and the results from member // functions of it may be cached and re-used, as long as some locale object refers // to that facet. static std::locale loc(default_locale()); #ifdef BOOST_FILESYSTEM_DEBUG std::cout &lt;&lt; "***** path_locale() called" &lt;&lt; std::endl; #endif return loc; } </pre> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Wed, 26 Apr 2017 18:24:18 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:6</guid> <description> <p> I currently tend to favour to accept this pull request: </p> <p> <a class="ext-link" href="https://github.com/boostorg/filesystem/pull/43"><span class="icon">​</span>https://github.com/boostorg/filesystem/pull/43</a> </p> <p> It has the advantage to localize the algorithm decision logic and doesn't need to change the calling signature of <code>equal_string_ordinal_ic</code> in such an ugly way. I would like to test it tomorrow on different systems. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Wed, 26 Apr 2017 18:36:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:7</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12987#comment:5" title="Comment 5">Leinad</a>: </p> <blockquote class="citation"> <p> Yes that's correct. I think it's a c++11 feature, but we use this already in path.cpp: </p> <pre class="wiki"> std::locale&amp; path_locale() [...] return loc; } </pre></blockquote> <p> Exactly this function causes problems as described in issue <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>. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Leinad</dc:creator> <pubDate>Thu, 27 Apr 2017 10:59:56 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:8</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12987#comment:6" title="Comment 6">daniel.kruegler@…</a>: </p> <blockquote class="citation"> <p> I currently tend to favour to accept this pull request: </p> <p> <a class="ext-link" href="https://github.com/boostorg/filesystem/pull/43"><span class="icon">​</span>https://github.com/boostorg/filesystem/pull/43</a> </p> <p> It has the advantage to localize the algorithm decision logic and doesn't need to change the calling signature of <code>equal_string_ordinal_ic</code> in such an ugly way. I would like to test it tomorrow on different systems. </p> </blockquote> <p> I agree. That solution (pull request 43) eliminates the ugliness of the signature of <code>equal_string_ordinal_ic</code>, but is it any different in terms of local static initialisation thread safeness? Would it have the same limitations? </p> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Thu, 27 Apr 2017 11:28:50 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:9</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12987#comment:8" title="Comment 8">Leinad</a>: </p> <blockquote class="citation"> <p> I agree. That solution (pull request 43) eliminates the ugliness of the signature of <code>equal_string_ordinal_ic</code>, but is it any different in terms of local static initialisation thread safeness? Would it have the same limitations? </p> </blockquote> <p> IMO it has similar limitations and I'm working on a variant of that proposal that fixes the thread-safeness problem. </p> </description> <category>Ticket</category> </item> <item> <author>daniel.kruegler@…</author> <pubDate>Sat, 29 Apr 2017 14:50:01 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:10</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12987#comment:9" title="Comment 9">daniel.kruegler@…</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12987#comment:8" title="Comment 8">Leinad</a>: </p> <blockquote class="citation"> <p> I agree. That solution (pull request 43) eliminates the ugliness of the signature of <code>equal_string_ordinal_ic</code>, but is it any different in terms of local static initialisation thread safeness? Would it have the same limitations? </p> </blockquote> <p> IMO it has similar limitations and I'm working on a variant of that proposal that fixes the thread-safeness problem. </p> </blockquote> <p> Daniela has now provided a revised resolution (very similar to her original one), which realizes that initialization happens in the (dynamic) program initialization phase (as the original approach did) and doesn't depend on local statics: </p> <p> <a class="ext-link" href="https://github.com/boostorg/filesystem/pull/43/commits/24240ed577229eb9568fd8050b9ca4233be92116"><span class="icon">​</span>https://github.com/boostorg/filesystem/pull/43/commits/24240ed577229eb9568fd8050b9ca4233be92116</a> </p> <p> It has been successfully tested against Visual Studio versions 2008, 2010, 2012, 2013, 2015, and 2017 and against MinGW with gcc 8 HEAD. I recommend to accept that PR. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Wed, 03 May 2017 14:15:36 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:11</guid> <description> <p> Is it thread safe? </p> <pre class="wiki">#include &lt;boost\filesystem.hpp&gt; const int thread_num = 10; boost::barrier barrier(thread_num + 1); bool c = [] { std::vector&lt;std::thread&gt; threads; for (int i = 0; i &lt; thread_num; ++i) { threads.emplace_back([] { barrier.wait(); boost::filesystem::exists("c:"); }); } barrier.wait(); for (auto&amp; thread: threads) thread.join(); return true; }(); int main(int argc, char* argv[]) { return 0; } </pre><p> <code>c</code> could be (probably is) initialised before <code>compare_function_initializer</code> in the unnamed namespace in operations.cpp. All those threads will call <code>compare()</code> and there might be race condition at reading/setting <code>compare_function</code>. </p> <p> I guess on many platforms reading/assigning a pointer is atomic in practice, and <code>GetProcAddress</code> and <code>GetModuleHandle</code> are thread-safe, too, so this is not an issue here. </p> </description> <category>Ticket</category> </item> <item> <author>o.tristan@…</author> <pubDate>Fri, 18 Aug 2017 17:01:36 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:12</guid> <description> <p> Is upcoming boost 1.65 still affected by this bug ? </p> </description> <category>Ticket</category> </item> <item> <author>Marcel Raad <Marcel.Raad@…></author> <pubDate>Fri, 25 Aug 2017 10:03:32 GMT</pubDate> <title>cc changed https://svn.boost.org/trac10/ticket/12987#comment:13 https://svn.boost.org/trac10/ticket/12987#comment:13 <ul> <li><strong>cc</strong> <span class="trac-author">Marcel.Raad@…</span> added </li> </ul> Ticket anonymous Mon, 25 Sep 2017 13:38:48 GMT <link>https://svn.boost.org/trac10/ticket/12987#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:14</guid> <description> <p> I'm using boost 1.65 with VS2015 and I still have this problem. </p> </description> <category>Ticket</category> </item> <item> <author>Ilia <ki.stfu@…></author> <pubDate>Tue, 03 Oct 2017 10:11:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:15</guid> <description> <p> I'm using boost 1.65.1 with VS2017 and I still have this problem. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Crl</dc:creator> <pubDate>Wed, 11 Oct 2017 10:20:45 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:16</guid> <description> <p> We switched from 1.63 to 1.65.1 recently and we also encounter this issue. Is there a workaround? When can we expect a patch for this issue? </p> </description> <category>Ticket</category> </item> <item> <author>pericles@…</author> <pubDate>Sun, 14 Jan 2018 06:07:39 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:17</guid> <description> <p> This bug is fixed in boost 1.66? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Mon, 15 Jan 2018 10:25:13 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12987#comment:18 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12987#comment:18</guid> <description> <p> Nop. But will probably be in 1.67 See <a class="ext-link" href="https://github.com/boostorg/filesystem/pull/43"><span class="icon">​</span>https://github.com/boostorg/filesystem/pull/43</a> </p> </description> <category>Ticket</category> </item> </channel> </rss>