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

James Y Knight via cfe-dev cfe-dev at lists.llvm.org
Mon Jul 23 14:38:02 PDT 2018


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).
>
> --
> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180723/a02d5b14/attachment.html>


More information about the cfe-dev mailing list