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

James Y Knight via cfe-dev cfe-dev at lists.llvm.org
Fri Jul 27 10:17:00 PDT 2018


I'm totally on board with a compiler flag.

But I still wonder a bit if we really need to add an attribute, considering
that you can already effectively create a global which doesn't run its
destructor, by creating a library type which placement new's into an
aligned_storage member.

That works within today's standard c++, without needing to add any
extensions. Now -- the main downside of the aligned_storage solution is
that its constructor cannot be constexpr, even if the underlying type is,
since placement new is not allowed in constexpr functions.

However, apparently the solution using a union will become correct in
C++20, if P0784
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0784r1.html> is
accepted:

template <typename T>
union NoDestroy {
  template <typename... Ts>
  explicit constexpr NoDestroy(Ts&&...args) :
val(std::forward<Ts>(args)...) {}
  explicit constexpr NoDestroy(T val) : val(val) {}
  /* not valid at the moment:*/ constexpr ~NoDestroy() {}
  T val;
};

ISTM that a type like that should probably be added to the standard library
in C++20, too, but if it isn't, users can write it themselves. (I'd also
note that even in earlier C++ versions, you can get away with omitting the
constexpr on the destructor, and your program will work fine. It is
_technically_ a violation of the standard to actually use the value after
the empty no-op destructor is notionally called, but since it does not
actually destroy the value contained in the union, it doesn't in practice
cause a problem.)


On Tue, Jul 24, 2018 at 7:45 PM JF Bastien <jfbastien at apple.com> wrote:

>
>
> On Jul 24, 2018, at 4:43 PM, Mehdi AMINI <joker.eph at gmail.com> wrote:
>
>
>
> Le mar. 24 juil. 2018 à 15:47, JF Bastien <jfbastien at apple.com> a écrit :
>
>>
>>
>> On Jul 23, 2018, at 2:38 PM, James Y Knight via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>> On some embedded systems I've had a chance to work with, it's quite
>> trivial to be certain nobody is relying on them, because they don't get
>> executed. If anyone thought they were relying on them for their
>> code...well, they were wrong. :)
>>
>> On Mon, Jul 23, 2018 at 4:16 PM Mehdi AMINI via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>>> Hi,
>>>
>>> On this topic, I work on an embedded system where I have these concerns
>>> about static destructor, but I can't either fully / blindly disable them.
>>> Disabling them with a global flag seems dangerous: how can I make sure that
>>> no-one is ever relying on it?
>>> Instead what I would need is an easy way to make sure that we control
>>> these destructor in the codebase as it evolves. For instance the attribute
>>> proposed above would be great,  and having the opposite positive attribute
>>> (expressing that I intend a static destructor) would be even better.
>>> Especially coupled with a warning for every static destructor emitted,
>>> since I can then use -Werrror to force every global to be annotated (or
>>> locally disable the warning if I include third-party code).
>>>
>>
>> I’ll do the flag as well as the attribute, and review your patch for the
>> warning? ;-)
>>
>
> Fair :)
>
>
>>
>
> To clarify: you're adding two attributes (positive and negative)?
>
>
> Yes.
>
>
> Thanks,
>
> --
> Mehdi
>
>
>
>
>>
>> I’ve got a few things on my plate at the moment, but I’ll get to this
>> ~soon and will CC those who replied to this email in the review.
>>
>>
>> --
>>> Mehdi
>>>
>>>
>>>
>>> Le mer. 18 juil. 2018 à 13:01, Richard Smith via cfe-dev <
>>> cfe-dev at lists.llvm.org> a écrit :
>>>
>>>> On Wed, 18 Jul 2018, 12:33 Aaron Ballman via cfe-dev, <
>>>> cfe-dev at lists.llvm.org> wrote:
>>>>
>>>>> On Tue, Jul 17, 2018 at 5:06 PM, JF Bastien via cfe-dev
>>>>> <cfe-dev at lists.llvm.org> wrote:
>>>>> > Replying to everyone so far. Thanks for the input!
>>>>> >
>>>>> > Based on feedback reveiced I think it makes sense to have an
>>>>> attribute, and
>>>>> > I’m happy to implement it. I also think a flag makes sense based on
>>>>> > developer feedback, and based on Ben’s reading of the standard for
>>>>> > freestanding. I don’t think we want to change the freestanding
>>>>> behavior (at
>>>>> > least not before C++20 cleans it up), but having a flag to control
>>>>> this
>>>>> > behavior makes sense.
>>>>> >
>>>>> > I therefore think we should pursue both.
>>>>> >
>>>>> > On attributes: I like this attribute for globals, function statics,
>>>>> and TLS.
>>>>> > I don’t like it at all for automatic variables, because RAII is
>>>>> fundamental
>>>>> > to C++. I think we should limit where the attribute can be used.
>>>>> >
>>>>> > Attribute name bikeshed: anyone care for one of
>>>>> >
>>>>> > [[no_destroy]]
>>>>> > [[indestructible]]
>>>>> > [[forever]]
>>>>> > [[undying]]
>>>>> > [[RAINI]] (Resource Acquisition Is Not Initialization)
>>>>> >
>>>>> > ?
>>>>>
>>>>> Out of that list, I think [[no_destroy]] resonates with me the most,
>>>>> but I don't have a strong preference. Other alternatives:
>>>>>
>>>>> [[destructor_not_run]]
>>>>> [[not_destroyed]]
>>>>> [[no_cleanup]]
>>>>>
>>>>> One question I have about any of these names is: can we check some
>>>>> very large bodies of code to ensure there are no use macros with the
>>>>> same spelling as whatever we seriously consider?
>>>>>
>>>>
>>>> Another thing we should consider: if we add both an attribute and a
>>>> flag, some users will reasonably want an attribute to undo the effect of
>>>> the flag. So we should pick a name for the attribute that supports a
>>>> negative form (either attr vs attr(false) or attr vs no_attr or something
>>>> like that).
>>>>
>>>> It'd also seem preferable to give the attribute and the flag names that
>>>> parallel one another, if we can do so without sacrificing name quality.
>>>> (Strawman: [[clang::no_destroy]] and -fno-destroy-statics)
>>>>
>>>> > Compiler flag name bikeshed: I’m happy with
>>>>> -fno-c++-static-destructors as
>>>>>
>>>>> I'd be happy with that flag name.
>>>>>
>>>>
>>>> Do we anticipate ever registering destructors for global ARC pointers
>>>> (or structs containing same)? If so, we may come to regret giving the flag
>>>> a C++-specific spelling.
>>>>
>>>> ~Aaron
>>>>>
>>>>> > Richard suggests.
>>>>> >
>>>>> >
>>>>> > Individual replies:
>>>>> >
>>>>> > Richard said:
>>>>> >
>>>>> > 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.
>>>>> >
>>>>> >
>>>>> > Agreed. Luckily some platforms already terminate program abruptly.
>>>>> These
>>>>> > applications already deal with those issues :-)
>>>>> >
>>>>> > 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
>>>>> > annotations
>>>>> > 3) (After some time has passed) switch the default from running
>>>>> destructors
>>>>> > to not running destructors
>>>>> >
>>>>> >
>>>>> > This path is interesting. I’ll write a paper for the next mailing,
>>>>> or during
>>>>> > the meeting, based on clang implementation experience and any usage
>>>>> I can
>>>>> > get between now and then. I’ll make sure to mention your suggestion.
>>>>> >
>>>>> > David said:
>>>>> >
>>>>> > I would; however, point out that exit() is not the only time that
>>>>> static
>>>>> > destructors are run.  The C++ standard pretends that shared
>>>>> libraries don’t
>>>>> > exist (and added thread-local variables with nontrivial destructors
>>>>> in such
>>>>> > a way that gives implementers two possible bad choices if they have
>>>>> to
>>>>> > support library unloading), but in the real world they do.  It’s
>>>>> difficult
>>>>> > to see how such a mode would coexist with a world that supports
>>>>> loading and
>>>>> > unloading of shared libraries.  Perhaps a sanitiser could check that
>>>>> the
>>>>> > objects have been destroyed when the library is unloaded?
>>>>> >
>>>>> >
>>>>> > I’d like to keep shared libraries out of scope of this discussion.
>>>>> >
>>>>> >
>>>>> >
>>>>> > On Jul 16, 2018, at 2:55 PM, JF Bastien via cfe-dev <
>>>>> cfe-dev at lists.llvm.org>
>>>>> > wrote:
>>>>> >
>>>>> > 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. We’ve discussed this previously 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.
>>>>> >
>>>>> >
>>>>> > 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).
>>>>> >
>>>>> > 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.
>>>>> >
>>>>> >
>>>>> > 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? 🤷‍♂️
>>>>> >
>>>>> >
>>>>> > Thanks,
>>>>> >
>>>>> > JF
>>>>> > _______________________________________________
>>>>> > cfe-dev mailing list
>>>>> > cfe-dev at lists.llvm.org
>>>>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>>> >
>>>>> >
>>>>> >
>>>>> > _______________________________________________
>>>>> > cfe-dev mailing list
>>>>> > cfe-dev at lists.llvm.org
>>>>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>>> >
>>>>> _______________________________________________
>>>>> cfe-dev mailing list
>>>>> cfe-dev at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>>>
>>>> _______________________________________________
>>>> cfe-dev mailing list
>>>> cfe-dev at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>>
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180727/7329de30/attachment-0001.html>


More information about the cfe-dev mailing list