On 15 August 2017 at 11:24, Richard Biener <richard.guent...@gmail.com> wrote: > On Tue, Aug 15, 2017 at 6:44 AM, Ron <r...@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().