<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jul 18, 2016, at 2:08 PM, Richard Smith via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><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" class=""><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br class="">
<br class="">
C++ static destructors can be problematic in multi-threaded<br class="">
environment. Some of the issues users often complain about include:<br class="">
1. Teardown ordering: crashes when one thread is exiting the process<br class="">
and calling destructors while another thread is still running and<br class="">
accessing the destructing variables<br class="">
2. Shared code that is compiled both as an application and as a<br class="">
library. When library mode is chosen, goto (1).<br class="">
3. Some projects currently override __cxa_atexit to avoid the behavior<br class="">
in question.<br class="">
<br class="">
To get around that, I propose we add a compiler option (e.g.<br class="">
-fno-cxx-static-destructors) to allow clang to suppress destructor<br class="">
registration (currently done via __cxa_atexit, atexit):<br class="">
<a href="https://reviews.llvm.org/D22474" rel="noreferrer" target="_blank" class="">https://reviews.llvm.org/D22474</a><br class="">
<br class="">
I'm opening this discussion here on cfe-dev to get some feedback on the matter<br class="">
<br class="">
One can argue that dealing with C++ static destructors in<br class="">
multi-threaded environment is solely the responsibility of the<br class="">
developer, however since (AFAIK) we don't have any standard guaranteed<br class="">
semantic for "global destruction vs. threads", it seems fair to me<br class="">
that we could give developers some option.</blockquote><div class=""><br class=""></div><div class="">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 class=""></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><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">There are standard techniques to avoid destructors being run for specific objects:</div><div class=""><br class=""></div><div class="">  template<typename T> union not_destroyed {</div><div class="">    T value;</div><div class="">    template<typename ...U> constexpr not_destroyed(U &&...u) : value(std::forward<U>(u)...) {}</div><div class="">    ~not_destroyed() {} </div><div class="">  };</div><div class="">  not_destroyed<std::string> my_str("foo"); // technically has object lifetime issues</div></div></div></div></div></blockquote><div><br class=""></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><br class=""></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><br class=""></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><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">  std::string &&s = *new std::string("foo");</div></div></div></div></div></blockquote><div><br class=""></div>This didn't compile.</div><div><br class=""></div><div>    test.cxx:12:26: error: rvalue reference to type 'basic_string<[3 * ...]>' cannot bind to lvalue of type 'basic_string<[3 * ...]>'<br class=""><br class=""></div><div><br class=""></div><div>-- </div><div>Greg Parker     <a href="mailto:gparker@apple.com" class="">gparker@apple.com</a>     Runtime Wrangler</div><div><br class=""></div><div><br class=""></div></body></html>