This is the mail archive of the gcc-patches@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: [RFC] C++ vs forced unwinding


On Tue, 8 Apr 2003 08:44:19 -0700, "Mark Mitchell" <mark at codesourcery dot com> wrote:

>> >> Hmm... I'm not sure that was a good decision.
>> >> Was the ISO C++ committee consulted at all about that?
>> >> Is the decision set in stone already?
>> >
>> > Pretty much.
>>
>> I disagree.
>
> Fair enough.  But people have already implemented it, at least.

Who, HP?  They chose to let longjmp_unwind go through throw()?

Mostly, I was disagreeing that the C++ committee had anything to say about
the issue.  longjmp_unwind is an extension dreamed up by the ABI
committee, and I don't remember the topic of exception specifications ever
coming up during discussions of forced unwind.

>> > Remember that plain longjmp can penetrate throw() if there are no
>> > automatic objects that would be destroyed.
>>
>> Sure.  longjmp_unwind must reach the setjmp point.  It's not clear that
>> it must do this by unwinding.  If unwinding fails, it could fall back on
>> plain longjmp.
>
> Consider:
>
>   struct S { ~S(); };
>
>   void f() throw () { longjmp_unwind (...); }
>
>  void g()  { S s; }

I assume you want a call to f() after the declaration of 's' here.

>   void h() {
>      setjmp (...);
>      g();
>   }
>
> So, you're saying we would get back to the setjmp point, but not destroy the
> local variable s in g?

If we make that choice, yes.

> That would leave the program in an inconsistent state.  I thought the whole
> point of longjmp_uwind was to avoid that particular inconsistent state.

The point was to play nice with C++; the question is what that means in
this situation.  I don't think it's clear what the right answer is.

It seems attractive to consider exception specs as analogous to catch
handlers; the ABI allows catch(...) handlers to run, but says that
unwinding must proceed after the handler has been executed.  One could
argue that the same should be true of exception specs, so unwinding should
proceed.  The other perspective is that the point of this requirement is
not unwinding per se, but just that the handler must not prevent the
longjmp_unwind from reaching the setjmp point.

longjmp_unwind will need to be able to fall back on plain longjmp in any
case, if unwinding fails for other reasons.  One example would be a
function with no unwind info).  And what if we call a cancellation point
from within an exception cleanup?  Normal unwinding would call terminate().
It seems to me that the best longjmp_unwind could do in that case would be
to fall back on plain longjmp.  In general, it seems that in the context of
longjmp_unwind, calls to terminate() should be replaced by plain longjmp.

But what should we do about throw()?

The consequences of allowing longjmp_unwind to unwind through throw():

 The optimization advantages of throw() are lost.  To get them back, users
 will need to know to annotate their functions with an attribute to be named
 later which asserts that the function will not be cancelled, either.  Or
 rely on compiler inter-procedural optimizations which don't exist yet.

 Assuming that a throw() function will only return normally (or not at all),
 so the caller doesn't need to practise exception safety, is no longer valid.

The consequences of not allowing longjmp_unwind to unwind through throw():

 Calling longjmp or a cancellation point from within a throw() function will
 fail to clean up objects in enclosing functions.  In effect, this means
 that a function which does I/O should not be declared throw().

Jason


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