<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Jul 19, 2016 at 10:34 AM Eric Fiselier <<a href="mailto:eric@efcs.ca">eric@efcs.ca</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Jul 19, 2016 at 9:13 AM, David Blaikie via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><br><div class="gmail_quote"><div><div class="m_-4478681893134045198h5"><div dir="ltr">On Mon, Jul 18, 2016 at 3:13 PM Greg Parker via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div>On Jul 18, 2016, at 2:08 PM, Richard Smith via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:</div><br><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Jul 18, 2016 at 1:39 PM, Bruno Cardoso Lopes via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
C++ static destructors can be problematic in multi-threaded<br>
environment. Some of the issues users often complain about include:<br>
1. Teardown ordering: crashes when one thread is exiting the process<br>
and calling destructors while another thread is still running and<br>
accessing the destructing variables<br>
2. Shared code that is compiled both as an application and as a<br>
library. When library mode is chosen, goto (1).<br>
3. Some projects currently override __cxa_atexit to avoid the behavior<br>
in question.<br>
<br>
To get around that, I propose we add a compiler option (e.g.<br>
-fno-cxx-static-destructors) to allow clang to suppress destructor<br>
registration (currently done via __cxa_atexit, atexit):<br>
<a href="https://reviews.llvm.org/D22474" rel="noreferrer" target="_blank">https://reviews.llvm.org/D22474</a><br>
<br>
I'm opening this discussion here on cfe-dev to get some feedback on the matter<br>
<br>
One can argue that dealing with C++ static destructors in<br>
multi-threaded environment is solely the responsibility of the<br>
developer, however since (AFAIK) we don't have any standard guaranteed<br>
semantic for "global destruction vs. threads", it seems fair to me<br>
that we could give developers some option.</blockquote><div><br></div><div>They already have options. They can use std::quick_exit, which was added specifically to address this problem, if they don't want destructors to be run at all. </div></div></div></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>std::quick_exit() does not help. The destructor is in a library. The library author has no control over how other code in the process calls exit(). The authors of the app and other libraries are unaware that exit() is dangerous.</div></div></div><div style="word-wrap:break-word"><div><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>There are standard techniques to avoid destructors being run for specific objects:</div><div><br></div><div>  template<typename T> union not_destroyed {</div><div>    T value;</div><div>    template<typename ...U> constexpr not_destroyed(U &&...u) : value(std::forward<U>(u)...) {}</div><div>    ~not_destroyed() {} </div><div>  };</div><div>  not_destroyed<std::string> my_str("foo"); // technically has object lifetime issues</div></div></div></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>This is fragile. It's easy to accidentally define a static variable that does not have this template, thereby breaking exit() again.</div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><br></div><div>-Werror=exit-time-destructors complains about ~not_destroyed(), so it can't help. Adding #pragma diagnostic around every use of not_destroyed would fix that and not be fragile, but it would be awfully ugly.</div></div></div></blockquote><div><br></div></div></div><div>I think not_destroyed could be written differently so as not to have a non-trivial dtor. Make it more like std::optional (wrapping an object in a pointer-like API) & just has a byte buffer member and no dtor declared. Then it'd be trivially destructible and have no global dtor and be -Wexit-time-destructors clean.</div></div></div></blockquote><div><br></div><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Clang seems to have no problem removing the call to the empty dtor at -O1.</div></div></div></div></blockquote><div><br></div><div>Making correctness dependent on optimizations is a bit tricky (though since the dtor does nothing, it's not actually a correctness issue - it's a global dtor that can't really race with anything, etc). But that's hard to detect in general - so we settle for a fairly blunt/defensible position of "not actually executing any code".</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> Using a byte buffer can have other problems, like losing the possibility of constant initialization.</div></div></div></div></blockquote><div> </div><div>Sure enough.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span><div style="word-wrap:break-word"><div><div><br></div><div>A post-link test for references to symbol __cxa_atexit might help, but only if there are no intentional static destructors anywhere and only for optimized builds. </div></div></div><div style="word-wrap:break-word"><div><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>  std::string &&s = *new std::string("foo");</div></div></div></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>This didn't compile.</div><div><br></div><div>    test.cxx:12:26: error: rvalue reference to type 'basic_string<[3 * ...]>' cannot bind to lvalue of type 'basic_string<[3 * ...]>'<br><br></div></div><div style="word-wrap:break-word"><div><br></div><div>-- </div><div>Greg Parker     <a href="mailto:gparker@apple.com" target="_blank">gparker@apple.com</a>     Runtime Wrangler</div><div><br></div><div><br></div></div></span><span>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</span></blockquote></div></div>
<br>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<br></blockquote></div></div></div></blockquote></div></div>