This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Behaviour of __forced_unwind with noexcept


On Tue, Aug 15, 2017 at 1:28 PM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 15 August 2017 at 11:24, Richard Biener <richard.guenther@gmail.com> wrote:
>> 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?
>
> If the forced_unwind exception escapes a noexcept function then the
> compiler calls std::terminate(). That can be replaced by the user so
> that it doesn't call abort(). It must not return, but a user-supplied
> terminate handler could trap or raise SIGKILL or something else.
>
> Required behavior: A terminate_handler shall terminate execution of
> the program without returning
> to the caller.
> Default behavior: The implementation’s default terminate_handler calls abort().
>
> I don't think glibc can help, I think the compiler would need to
> change to not call std::terminate().

Maybe it could call an unwinder provided hook so that forced_unwind can
set it to sth stopping the unwinding and signalling an error rather than
abort()ing.

Richard.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]