[cfe-dev] [RFC] Suppress C++ static destructor registration

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Mon Jul 16 18:46:17 PDT 2018

On Mon, 16 Jul 2018 at 14:55, JF Bastien via cfe-dev <cfe-dev at lists.llvm.org>

> Hi folks,
> I’d like to add a flag in clang, -fno-cxx-static-destructors,  which
> allows developers to demand that no static destructors be emitted. Bruno
> has a sample implementation <https://reviews.llvm.org/D22474>. We’ve discussed
> this previously
> <http://lists.llvm.org/pipermail/cfe-dev/2016-July/050040.html> but I’d
> like to re-open the discussion and make a different case for it because
> we’ve received more requests for such a feature.

(Nit: we generally prefer to use "c++" rather than "cxx" in flag names.)

*Why is this desirable?*
> In low-memory circumstances it’s often the case that we know that static
> global destructors are never called. It would be useful to avoid emitting
> them entirely to save memory. We can’t necessarily make the types
> themselves trivially destructible (e.g. a std::map, or a type that’s used
> both as a global and as an automatic variable for which the destructor is
> only meaningful when automatic, or coming from 3rd party library such as
> boost), and using a NeverDestroyed<T> class or global pointer only (std::string&
> foo = *new std::string(“derp");) prevents constexpr and is annoying
> boilerplate (and again, 3rd party code breaks that party).

Conversely, code (I'm also thinking particularly of third-party code) not
written to deal with no cleanup on termination may fail to flush buffers or
save changes to its configuration or the like, resulting in data loss. So
the user needs to do some work at some level -- either to verify it's safe
to turn this option on, or to change the code to avoid non-trivial
destruction -- and that work scales with the quantity of pre-existing
non-trivial destructors. Nonetheless, this flag may still be the most
pragmatic way to address the problems in question after determining that
it's safe to use it.

> This is also useful for some thread-related use cases: we have empirical
> evidence that threads using globals cause crashes if these globals are
> being destroyed.
> Thread-local storage is similarly painful for different reasons. I’m not
> proposing that anything be done yet, but let’s keep it in mind.
> *Developers want this?*
> Yes, we’ve received numerous requests for this. Developers are worried
> about code footprint, and have numerous crash reports they’d like to get
> rid of. Developers tell us they’d really rather not pay for this feature,
> because they don’t want to use it yet are stuck with it (and C++ is a
> “don’t pay for what you don’t use” language).
> Interesting note: developers are used to having no cleanup on termination
> on platforms where applications can get terminated when e.g. they’re sent
> to the background by user action.
> *Concrete example*
> Greg Parker provided this example of thread-related issues in the previous
> discussion:
> The Objective-C runtime has a global table that stores retain counts.
> Pretty much all Objective-C code in the process uses this table. With
> global destructors in place this table is destroyed during exit(). If any
> other thread is still running Objective-C code then it will crash.
> Currently the Objective-C runtime avoids the destructor by initializing
> this table using placement new into an aligned static char buffer.
> I’m assuming that the embedded usecase is obvious enough to everyone to
> not need an example. Let me know if that’s not the case.

I find the "I'm not going to exit(), so don't waste storage on destructors
I will never use" case much more compelling than the "my destructor is
wrong so please don't run it" case.

*What about standardization?*
> If this works out I'll discuss standardization options through SG14 (and
> then WG21). The type of developer who’s asked for this are typical SG14
> targets (embedding, gaming, etc). This might fit in with “freestanding” or
> other similar SG14 efforts, but we need experience to guide the proposal.
> Maybe EWG will be interested as well? 🤷‍♂️

Somewhat echoing my comments on the previous thread... if we're
implementing something that is also being proposed for standardization
(even if that's going to be via a TS or other side-standard), I think you
have a much stronger case for this change than if we're adding yet another
non-standard C++ dialect (or, more accurately, doubling the number of such
dialects). See the guidelines for language extensions at
http://clang.llvm.org/get_involved.html -- I have no doubt that you can
address all points here other than 3 and 4, and if you have a paper
describing a specification for this feature heading through WG21 with "a
reasonable chance of acceptance", that seems to satisfy those two remaining

On the standardization front, I think there is a path to changing ISO C++
that has at least some chance of success:
1) Add an annotation mechanism to say "this variable intentionally has a
non-trivial destructor that must be run at shutdown" and another to say
"this variable should not have its destructor run at shutdown even though
it's non-trivial"
2) Deprecate variables with a non-trivial destructor without one of those
3) (After some time has passed) switch the default from running destructors
to not running destructors

Perhaps we should consider such annotations alongside the flag?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180716/b8b52062/attachment.html>

More information about the cfe-dev mailing list