Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2002-09-28 13:54:43


David Abrahams wrote:
[...]
> > wrong. In any event, our service folks really want to see a full dump,
> > instead of kinda silly: "catch(const std::exception& e) { cerr <<
> > e->what(); exit( EXIT_FAILURE ); }"-like stuff.
>
> OK. Sounds like the sort of thing that could be implemented at the library
> level, if only everyone would cooperate and use the facilities. Maybe we
> need a Boost error-handling library.

Maybe. On the longer run, however, I'd really prefer that you and a
couple of others *rethink* exception handling facilities in C++ and
kinda fix them. What I personally wish in the first place, is that
unless I catch an exception, no unwinding shall take place; exception
specifications shall act just like "fences" [for the initial search
phase] resulting in std::unexpected() *invoked at throw point*, for
example. Other "goodies" might be added as well.

> Sounds like with all these
> nasty-C++-implementation-choices and thread cancellation safety issues,

Well, I just hope that Christophe won't kill me for publishing here
in public my reply to his private message (in reply to my other
comp.std.c++ posting). I also hope that enough folks here will buy
his[/IEEE] article on exception handling and optimizations -- this
might, perhaps, kinda compensate my violation of privacy code, so
to speak. ;-)

cc:
Subject: exception handling -- forced unwinding

Hi Christophe,

Thanks for the reply and the link to the article.

> In other words, catch(...) will *not* see it.

Ha! But that's still ``doesn't-work-at-all!'' ;-) Seriously,
I really can't make any sense of the idea of *forced* unwinding,
in general. To begin with, it would break rather important [you
even mention it in your article, AFAICS] throw() exception specs,
throw(something) aside for a moment.

It would also break legal code like this:

  /* allocate resources -- >>no RAII<< */

  try {
    /* can't tolerate forced unwinding initiated inside try here */
  }
  catch(...) {
    /* nothrow code here */
  }

  /* free resources */

and other "variations" that all depend on just-can't-miss-"..."-block-and/
or-the-code-below-it informal semantics of that nice try{/**/}catch(...){/**/}
thing.

As for the thread cancel/exit... that ought to be normal C++ exceptions;
just like any other SEH/C-exception beast, I believe [but there should be
a way to control "hardware"/synchronous-signals stuff ala exc_raise_signal
_exception()[1]; here I somewhat disagree with a few bits in your article,
BTW].

Foreign exceptions [e.g. Java ones while flying (if allowed-via-ex.specs
and/or *expected*-via-catch-handlers ;-) ) over C++ land] should probably
be represented in C++ code as sort of "handles" -- one single C++ exception
type encapsulating all possible foreign exceptions coming from that particular
land/"runtime". Alternatively, perhaps as sort of extension, I'd probably
want to have "a mapping mechanism" that would support native representations
for all exceptions in each and every "runtime" [but that might be rather
problematic, so to speak, I think ;-) ].

setjmp/longjmp is already way too restricted [and that's good], so that it's
practically unusable in C++ code... from "modular programming" point of view,
at least.

IOW, I don't see *any need* for forced unwinding [DEC->Compaq->HP's
exc_capture_context()/exc_longjmp()[2] including ;-) ].

What am I missing here?

regards,
alexander.

[1] http://tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9MBTE/VNTPRCSS.HTM#exc-sig-hand-coexistence
[2] http://tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/MAN/MAN3/0022____.HTM

----- [Original Message, forwarded, quoted] -----
From: "Alexander Terekhov" <terekhov_at_[hidden]>
Subject: Fwd:
Sent: Friday, July 19, 2002 9:57 PM

> "DE-DINECHIN,CHRISTOPHE <snip> schrieb am 19.07.02 19:49:24:
> > I've been part of the design of the exception handling for Itanium. I wrote
> > an article on the subject, which you can find here:
> > <http://www.computer.org/concurrency/pd2000/p4072abs.htm>. It should clear a
> > few things up on why we do things that way on Itanium.
> >
> > Contrary to your assumption, the "exception" mentionned in the document is
> > an exception only from the runtime point of view, not from the C++ point of
> > view. In other words, catch(...) will *not* see it. If a compiler generates
> > code where a longjmp causes you to execute code in a catch(...), that
> > compiler has a serious bug :-)
> >
> > > Well, one problem {among couple of others} is that C++ language has
> > > 'a catch thing' with three dots in it:
> > >
> > > try{/**/}/**/catch(...){/**/}
> >
> > My understanding is that the "user-defined code" that the original document
> > refers to is not normally intended to cover such catch-all clauses. Rather,
> > it is intended to let the compiler not have to duplicate code unnecessarily
> > just to avoid some user code. I'll try to illustrate this below.
> >
> > Basically, the Itanium EH model is intended to avoid paying an "exception
> > tax" on the non-exceptional path, even if it means doing more complicated
> > things in case of exceptions. Empirically, on PA-RISC, we observed around
> > 10% performance loss because of EH in some cases, simply because there were
> > optimizations on the regular path that the compiler didn't dare doing
> > anymore. For instance, moving code past a function call. Consider this:
> >
> > try
> > {
> > int a = 0;
> > foo();
> > a = 1;
> > // More code
> > } catch(...)
> > {
> > cout << "a=" << a;
> > }
> >
> > In that case, the foo() function has no way to see the value of a (no
> > address taken). So we can just remove the code that sets a=0 on the
> > non-exceptional path. But then, if an exception is taken, we need to patch
> > up. For instance, the code is rewritten as something like (I'm simplifying,
> > a lot):
> >
> > foo();
> > a = 1;
> > // More code
> > goto after_the_catch;
> >
> > catch_cleanup_code:
> > a = 0;
> > switch(exception_type)
> > {
> > case UNWINDING_FOR_LONGJMP_OR_PTHREAD_CANCEL:
> > ResumeUnwind();
> > default:
> > cout << "a=" << a;
> > }
> >
> > So the "user code" that the text refers about would be the "a=0", not the
> > catch(...) code. Now, why do we need to reinsert that code "a=0" along the
> > path for something like longjmp(), you may ask. The main motive is to avoid
> > duplication of code. The same restoration code also needs to restore
> > registers that the caller will use (for instance, the register where the
> > caller saved the return pointer, otherwise the longjmp() caller would not be
> > able to return itself). We wanted to avoid forcing the compiler to duplicate
> > that path, once for the "setjmp/pthread" unwinding and once for the normal
> > EH case. Note that a lot of this "code" is real code, a lot is unwinding of
> > registers done by the runtime by manipulating the EH stack directly.
> >
> >
> > I hope this clarified things...
> > Christophe
> >
> > "Alexander Terekhov" <terekhov_at_[hidden] <mailto:terekhov_at_[hidden]>> wrote in
> > message
> > <news:3D205A8A.DEFC922A_at_[hidden]>...
> > > Explanation [relevance w.r.t. C++ exceptions 'model']:
> > >
> > > A) longjmp and C++ exceptions:
> > >
> > > The standard says: "The function signature longjmp(jmp_buf jbuf, int
> > val)
> > > has more restricted behavior in this International Standard. If any
> > automatic
> > > objects would be destroyed by a thrown exception transferring control
> > to
> > > another (destination) point in the program, then a call to
> > ongjmp( jbuf, val)
> > > at the throw point that transfers control to the same (destination)
> > point has
> > > undefined behavior.
> > >
> > > Now, of course, any implementation MAY define whatever behavior it
> > wants for
> > > everything left undefined in the standard [portability aside]...
> > however,
> > > unwinding via-an-exception-that-simply-can't-be-finally-caught ["no
> > language
> > > is allowed to 'catch'"] doesn't really work in C++, AFAICS; please
> > see the
> > > next (B)-item below;
> > >
> > > B) "it does not need to know anything specific about unwinding
> > > done on behalf of longjmp or pthreads cancellation":
> > >
> > > Well, one problem {among couple of others} is that C++ language has
> > > 'a catch thing' with three dots in it:
> > >
> > > try{/**/}/**/catch(...){/**/}
> > >
> > > Now, "User-defined code in a catch clause may still be executed,
> > > but the catch clause must resume unwinding with a call to
> > > _Unwind_Resume when finished. " is basically nothing but
> > > 'auto_rethrow_exception' and 'catch(...)' illustrated here
> > > [transformations of 'legal-throws' into 'now-suddenly-colliding-
> > > throws' plus Ex.Specs 'fencing' aside, for a moment]:
> > >
> > > <http://lists.boost.org/MailArchives/boost/msg23046.php>
> > >
> > > It simply doesn't work, unless I'm just missing something...
> > > then I apologize in advance for the noise.
> > >
> > > > > Also, I'm still awaiting some answer to a couple of 'questions'
> > > > > [misconceptions (AFAICT/IMNSHO)] hinted, for example, here:
> > > > >
> > > > > <http://groups.google.com/groups?selm=3CF802FB.98E837E9%40web.de>
> > > >
> > > > I looked there. I don't see any questions to answer, other than "or am I
> > > > wrong, folks?" at the end.
> > >
> > > Well, another question was [w/o corresponding question mark, though ;-) ]:
> > >
> >


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk