Behaviour of __forced_unwind with noexcept

Richard Biener richard.guenther@gmail.com
Tue Aug 15 11:18:00 GMT 2017


On Tue, Aug 15, 2017 at 6:44 AM, Ron <ron@bitbabbler.org> wrote:
> On Mon, Aug 14, 2017 at 06:22:39PM +0100, Jonathan Wakely wrote:
>> On 13 August 2017 at 19:20, Ron wrote:
>> >
>> > Hi,
>> >
>> > I'm looking for some clarification of how the __forced_unwind thread
>> > cancellation exceptions intersect with noexcept.  I've long been a
>> > big fan of the __forced_unwind idiom, but now that C++14 is the default
>> > since GCC 6.1, and many methods including destructors are implicitly
>> > noexcept, using it safely appears to have become a lot more tricky.
>> >
>> > The closest I've found so far to an "authoritative" statement of the
>> > expected behaviour is the comments from Jonathan Wakely here:
>> >
>> > https://stackoverflow.com/questions/14268080/cancelling-a-thread-that-has-a-mutex-locked-does-not-unlock-the-mutex
>> >
>> > In particular: "It interacts with noexcept as you'd expect:
>> > std::terminate() is called if a __forced_unwind escapes a noexcept
>> > function, so noexcept functions are really noexcept, they won't
>> > unexpectedly throw some 'special' type"
>> >
>> > Which does seem logical, but unless I'm missing something this makes
>> > it unsafe to perform any operation in a destructor which might cross
>> > a cancellation point, unless that destructor is noexcept(false).
>>
>> Unfortunately I still think that's true.
>>
>> This was also raised in https://gcc.gnu.org/ml/gcc-help/2015-08/msg00040.html
>
> Ouch.  Had you considered the option of having any scope that is
> noexcept(true) also be treated as if it was implicitly in a scoped
> pthread_setcancelstate(PTHREAD_CANCEL_DISABLE), restoring the
> old state when it leaves that scope?
>
> Would it be feasible for the compiler to automatically generate that?
>
> For any toolchain which does use the unwinding exceptions extension,
> that also seems like a logical extension to the noexcept behaviour,
> since allowing cancellation will otherwise result in an exception and
> process termination.  If people really need cancellation in such
> scopes, then they can more manageably mark just those noexcept(false).
>
>
> It would need to be done by the compiler, since in user code I can't
> do that in a destructor in a way that will also protect unwinding
> members of a class (which may have destructors in code I don't
> control).
>
> I can't even completely mitigate this by just always using -std=c++03
> because presumably I'm also exposed to (at least) libstdc++.so being
> built with the new compiler default of C++14 or later.
>
>
> I'd be really sad to lose the stack unwinding we currently have when
> a thread is cancelled.  I've always known it was an extension (and I'm
> still a bit surprised it hasn't become part of the official standard),
> but it is fairly portable in practice.
>
> On Linux (or on Debian at least) clang also supports it.  It's also
> supported by gcc on FreeBSD and MacOS (though not by clang there).
> It's supported by mingw for Windows builds.  OpenBSD is currently
> the only platform I know of where even its gcc toolchain doesn't
> support this (but they're also missing support for standard locale
> functionality so it's a special snowflake anyway).
>
>
> It seems that we need to find some way past the status-quo though,
> because "don't ever use pthread_cancel" is the same as saying that
> there's no longer any use for the forced_unwind extension.  Or that
> "you can have a pthread_cancel which leaks resources, or none at all".
>
> Having a pthread_cancel that only works on cancellation points that
> aren't noexcept seems like a reasonable compromise and extension to
> the shortcomings of the standard to me.  Am I missing something there
> which makes that solution not a viable option either?

Have glibc override the abort () from the forced_unwind if in pthread_cancel
context?

I guess sprinkling pthread_setcancelstate () around would be doable
(in some __cxxabi helper) but it might be quite expensive to do so...

Richard.

>
>> > And since that could be something as simple as logging to stdio and
>> > almost impossible to definitely rule out in a future proof way if the
>> > destructor does anything non-trivial (like calling functions in a
>> > system or other 3rd party library) ...  and since the race of catching
>> > a cancellation request in such a destructor could be a relatively rare
>> > one to lose in a lot of code ...  there could be a lot of extant code
>> > with new latent 'crasher' bugs when built with GCC 6.1 or later.
>> >
>> > And/or a lot of people are going to have to go through a lot of code
>> > and mark up a lot of methods with noexcept(false).
>> >
>> >
>> > So I'm half-hoping that I am actually missing something here which
>> > mitigates that - but if not, is this something we need to give a
>> > bit more thought to?
>> >
>> > (Please keep me cc'd, I'm not currently on this list)
>> >
>> >   Cheers,
>> >   Ron



More information about the Gcc mailing list