This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: catch(...) and forced unwind
- From: Nathan Myers <ncm at cantrip dot org>
- To: David Abrahams <dave at boost-consulting dot com>
- Cc: Jason Merrill <jason at redhat dot com>, gcc at gcc dot gnu dot org,Richard Henderson <rth at redhat dot com>,Mark Mitchell <mark at codesourcery dot com>,Ulrich Drepper <drepper at redhat dot com>,Benjamin Kosnik <bkoz at redhat dot com>, Jakub Jelinek <jakub at redhat dot com>,wekempf at cox dot net, fjh at cs dot mu dot oz dot au
- Date: Sat, 13 Dec 2003 19:59:09 -0800
- Subject: Re: catch(...) and forced unwind
- References: <xypwu91ofvf.fsf@miranda.boston.redhat.com> <ud6at1wvg.fsf@boost-consulting.com> <xypekv9nr9u.fsf@miranda.boston.redhat.com> <u65gkyhv4.fsf@boost-consulting.com>
On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
> Jason Merrill <jason@redhat.com> writes:
>
> > On Fri, 12 Dec 2003 17:42:27 -0500, David Abrahams
> >
> >> 2. There is some documentation somewhere which indicates that one of
> >> the functions called by tf is a "cancellation point" (i.e. may
> >> throw thread cancellation exceptions). Otherwise, it seems to me,
> >> "this high-level behavior" would not be wrong.
> >
> > Basically, all of the C library I/O functions are cancellation points.
>
> Well, I constider that very surprising. It harms the ability to write
> portable code, for reasons explained below.
Indeed, it's commmon to declare external C functions "throw()", meaning
no exceptions can ever come out of them, and expect the compiler to
optimize accordingly.
> >>> I believe this is a bug in the library: it thinks it knows what sorts of
> >>> exceptions it will see and wants to swallow all of them, but it is wrong.
> >>
> >> It's definitely not a bug if you're just considering the specification
> >> you quoted above. You must have some other criteria for saying it
> >> is. Care to share them?
> >
> > I don't expect writing 'cout << "."' to suppress thread cancellation.
> > Do you disagree that this is an extremely surprising side-effect?
>
> Yes, I disagree that it's surprising. I know that iostream operations
> won't throw unless you set badbit, and I therefore expect them not to
> throw.
>
> Knowing which operations can throw and which can't is crucial to
> writing exception-safe code (see
> http://www.boost.org/more/generic_exception_safety.html), regardless
> of the reasons for the exception. If you violate the guarantee that
> certain non-throwing operations won't throw, you fundamentally
> undermine people's ability to correctly deal with exceptions
> (e.g. clean up resources).
Not throwing is part of iostream's contract. For the runtime system
to arbitrarily change that contract makes any code written to the old
contract indeterminate and likely wrong.
> Furthermore, throwing against the standard's guarantees undermines
> portability. All code which can run in a cancellable thread now has
> to have special knowledge of the behavior of the system it's running
> on. That could mean, for example, that people can't pick up the Boost
> libraries and use them inside of a thread. This effect is bad with
> functions people don't *expect* to throw (the C I/O) but the standard
> does allow those to throw implementation-defined exceptions. It's
> *really really* bad with functions the standard guarantees won't
> throw.
Changing the semantics of C++ exceptions demands special versions of
every library, just for use in threaded programs on this one platform.
It will make most threaded programs not portable to this platform.
> >>> 2) explicitly rethrow cancellation--
> >>
> >> That seems to violate the specification you quoted.
> >
> > I don't think the specification is relevant in this case. Cancellation
> > uses the exception handling runtime but is not a normal exception;
>
> In what sense?
>
> > this is outside the scope of the current standard.
>
> I think it's not the nature of the exception, but the fact that you're
> running in a thread which makes it "outside the scope", since the
> standard doesn't cover threading. Still, the ability to use code in
> threads which was written without knowledge of your threading system,
> I would think, is crucial.
The population of coders willing to write code just for this one threading
system is necessarily small.
> >>> 3) don't catch and swallow all exceptions; changing the catch(...) to
> >>> catch(std::exception) would catch all exceptions thrown by other parts
> >>> of the library, which AFAIK is what we're trying to accomplish.
> >>
> >> That also seems to violate the specification you quoted.
> >
> > Yes, this would require a change in the standard.
> >
> >> Either you have to lobby to get the standard changed, live with the
> >> fact that you're going to break it, or live with the fact that not
> >> having badbit set will suppress cancellation in some circumstances. I
> >> don't think it's honest to "fix" the problem by calling the latter
> >> behavior a bug if that's what the specifications say to do.
> >
> > The specifications don't say anything about cancellation. We're in
> > extensions-land here, so we get to decide what it means. We can decide
> > that cancellation acts just like an exception, or we can decide that it
> > acts like an exception except when it doesn't. The standard may provide
> > guidance about what the best solution might be, but no more than that.
>
> I'm not sure I agree with you on the fine points, but regardless, I
> think the code interoperability arguments I made above indicate that
> you'd better not let exceptions propagate when the standard says they
> won't. It's a bad idea to let a non-standard extension completely
> change the assumptions code can make about its execution environment.
This is a difference from the C world. With C, no one expects a library
to work right in a threaded program if it wasn't written with that target
in mind. Contrarily, C++ users routinely expect portable C++ libraries
to be exception- and thread-safe, and an enormous amount of such code
has already been written that is. Changing the semantics of exception
handlers breaks it all.
The largest probable effect of this change in semantics would be for
library writers to warn against ever allowing thread cancellation in
any program that uses the library. In practice, it would mean that
thread cancellation is not available on this platform. It would be
odd to do all this work just to eliminate any possibility of usable
thread cancellation.
In the meantime, the ISO committee is discussing a standard threads
library for C++, including a cancellation model incompatible with what
is being proposed here. It would be better for everybody involved for
Gcc to match it.
For an operation as dubious as thread cancellation to demand a
fundamental change in language semantics, and a rewrite of so many
libraries, is a very small tail wagging a very big dog.
Nathan Myers
ncm@cantrip.org