Topic: Exception handling... it's time to fix the standard


Author: apm35@student.open.ac.uk (apm)
Date: Fri, 30 May 2003 18:15:26 +0000 (UTC)
Raw View
terekhov@web.de (Alexander Terekhov) wrote in message news:<3ED3AE8B.AEDAD52A@web.de>...
> "Terje Sletteb " wrote:
> I want to
> have the standard-mandated 2-phase exception processing with the
> exception specs acting as simple "barriers" during the 1st/search
> phase. All unexpected/uncaught exceptions should result in the
> invocation of std::unexpected() at their throw-points; that's due
> to the implicit restrictive ESes that I want to be given to all
> destructors [throw()]

The difficulty is in having stronger ESes that work in the presence of
templates such as those used in the STL. See
http://www.andrewmarlow.co.uk/publications.html for a proposal on
stronger ESes including a discussion of these, and other, issues.

Regards,

Andrew M.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Fri, 30 May 2003 20:01:36 +0000 (UTC)
Raw View
apm wrote:
>
> terekhov@web.de (Alexander Terekhov) wrote in message news:<3ED3AE8B.AEDAD52A@web.de>...
> > "Terje Sletteb " wrote:
> > I want to
> > have the standard-mandated 2-phase exception processing with the
> > exception specs acting as simple "barriers" during the 1st/search
> > phase. All unexpected/uncaught exceptions should result in the
> > invocation of std::unexpected() at their throw-points; that's due
> > to the implicit restrictive ESes that I want to be given to all
> > destructors [throw()]
>
> The difficulty is in having stronger ESes that work in the presence of
> templates such as those used in the STL.

Show me an example illustrating "the difficulty" with respect to
*destructors* having stronger (throw()-nothing) ESes, please.

>                                          See
> http://www.andrewmarlow.co.uk/publications.html for a proposal on
> stronger ESes including a discussion of these, and other, issues.

Uhmm, http://www.marlowa.plus.com/publications.html perhaps?

http://www.marlowa.plus.com/goodies/proposal.pdf
(A proposal to add static checking to C++ exception specifications.)

I'm NOT asking for "an extension to C++ in the area of exception
handling that is designed to facilitate static checking of
exceptions."

I can bombard-you-to-death with links on that, but I'll refrain.
(hoping that you'll take a chance and try to understand what I'm
talking about in this thread ;-) )

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: tslettebo@chello.no.nospam ("Terje Sletteb ")
Date: Tue, 27 May 2003 17:21:02 +0000 (UTC)
Raw View
"Alexander Terekhov" <terekhov@web.de> wrote in message
news:3EC0ECAA.6520B266@web.de...

I've read through your postings, but as they are long and detailed, with a
lot of references to other places, but without some kind of introduction
or summary, I found it hard to understand what your point was.

Could you have tried to restate what it is, in a introduction/summary
form?

This may also have contributed to lack of feedback to this thread, so far.


Regards,

Terje

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Tue, 27 May 2003 20:55:42 +0000 (UTC)
Raw View
"Terje Sletteb=F8" wrote:
>=20
> "Alexander Terekhov" <terekhov@web.de> wrote in message
> news:3EC0ECAA.6520B266@web.de...
>=20
> I've read through your postings, but as they are long and detailed, wit=
h a
> lot of references to other places, but without some kind of introductio=
n
> or summary, I found it hard to understand what your point was.
>=20
> Could you have tried to restate what it is, in a introduction/summary
> form?

As currently specified, exception specs not only catch unexpected=20
exceptions, but they also invoke "wrong" unexpected/terminate=20
handlers -- those that were in effect at throw-points (handlers=20
basically fly together with the unexpected exceptions). I want to=20
have the standard-mandated 2-phase exception processing with the=20
exception specs acting as simple "barriers" during the 1st/search=20
phase. All unexpected/uncaught exceptions should result in the=20
invocation of std::unexpected() at their throw-points; that's due=20
to the implicit restrictive ESes that I want to be given to all=20
destructors [throw()] and "threads" -- those should only throw=20
thread cancel/exit exceptions (things like exceptions with=20
throwing copy constructors, thowing atexit() handlers, and etc.=20
aside for a moment]. More "refinements" can be done if/once we=20
agree on that.

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Sun, 25 May 2003 14:18:56 +0000 (UTC)
Raw View
< "self-correction" [well, and "move up" ;-) ] >

> >                                            Finally, I believe
> >  that the standard should say that 'execution of each and
> >  every thread' [initial/main including] shall be done "as if"
> >
> >    whatever run(...whatever...) throw(std::thread_exit,
> >                                       std::thread_cancel);
>
> Sorry, std::thread_exit_request and std::thread_cancel_request
> (std::thread_termination_request aside for a moment ;-) ):
>
> http://groups.google.com/groups?selm=3EC258F8.AE7DF214%40web.de
>
> <quote>
>
> I can see nothing in the POSIX standard that would prohibit
> the following implementation of pthread_exit():
>
> extern "C" void pthread_exit(void * ptr) {
>   std::thread_exit(ptr);
> }

Sorry, I meant:

#define PTHREAD_CANCELED std::thread_canceled()

extern "C" void pthread_exit(void * ptr) throw(std::thread_termination_request) {
  (ptr == PTHREAD_CANCELED) ? std::thread_cancel() : std::thread_exit(ptr);
}

>
> using something along the lines of: (from the "std" namespace)

struct thread_canceled {
  operator void * () { return &unique; }
  static thread_canceled unique;
};

>
> class thread_termination_request : public std::exception ...
> class thread_cancel_request : public std::thread_termination_request ...
> class thread_exit_request : public std::thread_termination_request ...
>
> template<typename T>
> class thread_exit_value : public std::thread_exit_request ...
>
> template<typename T>
> void thread_exit(T value) {
>   assert(std::thread_self().can_exit_with<T>());
>   throw thread_exit_value(value);
> }

template<>
void thread_exit(std::thread_canceled) {
  thread_cancel();
}

void thread_cancel() {
  throw std::thread_cancel_request();
}

("or something like that").

regards,
alexander.

--
"Stroustrup is not a disinterested party in that debate."

            -- [Subject: Re: c#] http://tinyurl.com/ckem

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Thu, 15 May 2003 21:02:45 +0000 (UTC)
Raw View
Alexander Terekhov wrote:
[...]
>                                            Finally, I believe
>  that the standard should say that 'execution of each and
>  every thread' [initial/main including] shall be done "as if"
>
>    whatever run(...whatever...) throw(std::thread_exit,
>                                       std::thread_cancel);

Sorry, std::thread_exit_request and std::thread_cancel_request
(std::thread_termination_request aside for a moment ;-) ):

http://groups.google.com/groups?selm=3EC258F8.AE7DF214%40web.de

<quote>

I can see nothing in the POSIX standard that would prohibit
the following implementation of pthread_exit():

extern "C" void pthread_exit(void * ptr) {
  std::thread_exit(ptr);
}

using something along the lines of: (from the "std" namespace)

class thread_termination_request : public std::exception ...
class thread_cancel_request : public std::thread_termination_request ...
class thread_exit_request : public std::thread_termination_request ...

template<typename T>
class thread_exit_value : public std::thread_exit_request ...

template<typename T>
void thread_exit(T value) {
  assert(std::thread_self().can_exit_with<T>());
  throw thread_exit_value(value);
}

</quote>

>
>  is called; that implementation simply does finalization
>  of thread_exit or thread_cancel exception (if thrown)
>  resulting in thread termination and that any other uncaught
>  exception will end up in std::unexpected() invoked at throw
>  point.

I forgot to mention:

- make std::unexpected handlers thread-specific (keep
  std::terminate handers "enclave-wide")

- get rid of the totally broken "if called by the
  implementation" clause in 18.6.2.4/2. Details can
  be found in a thread here: <http://tinyurl.com/btje>
  (with std::unexpected invoked at throw point, there
   will be no difference at all with respect "if called
   by the program" or by the implementation)

- "weaken" function-try-block handlers for non-dtors
  (having implicit throw() ES, function-try-block for
  a dtor doesn't make sense). "weaken" means that it
  shall be "invisible" in the search phase and have
  "dtor-like" semantics during unwinding ala(*):

  <copy&paste>

  I'll admit that I'll have no problems with something like

  template<class _FwdIt, class _Tval> inline
  void _Uninit_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val,
          _Nonscalar_ptr_iterator_tag)
  {       // copy _Val throughout raw [_First, _Last), arbitrary type
    _FwdIt _Next = _First;
    try {
      for (; _First != _Last; ++_First)
        _Construct(&*_First, _Val);
    }
    action_on_propagation_of(...) {  /* THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS */
                                     /* THIS DOES RETHROW EXCEPTIONS AUTOMATICALLY */
                                     /* NOTHING ELSE CAN BE THROWN FROM THIS SCOPE */
      for (; _Next != _First; ++_Next)
        _Destroy(&*_Next);
    }
  }

  </copy&paste>

  more info on this: <http://tinyurl.com/bthu>.

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Tue, 13 May 2003 15:11:04 +0000 (UTC)
Raw View
G'Day,

A) http://tinyurl.com/bdp1

  "Arrgh!  Now I understand why you are unhappy about this.
   This goes against everything I'd understood about the way
   exceptions worked."

B) <Forward Inline>

<-------- Original Message -------->
Message-ID: <3EC0E634.D5B14ACB@web.de>
Newsgroups: comp.lang.c++
Subject: Re: does throw() imply any type of performance difference?

stephan beal wrote:
>
> Hello!
>
> i've got a high-usage class which i'm trying to optimize a bit, and i have a
> question about the throw() clause:
>
> class Foo {
>   inline void foo() throw() {...};
> };
>
> Question: does the addition of throw() give a compiler any implicit
> permission (or leeway) to add any sort of exception-handling code to that
> function. More precisely, does the inclusion of this keyword, in and of
> itself, it allow the compiler to make any changes which might affect the
> runtime performance of function foo(), compared to the output generated
> when foo() does not throw()? (The point being, if it does then i want to
> remove them from this particular class.)
>
> i would greatly appreciate any clarification on that point.

Unfortunately, throw() implies [due to totally broken semantics
specified in the {current} C++ standard] a function-try-block with
catch(...) handler that invokes std::unexpected(). Broken standard
aside for a moment(*), throw() really-really helps optimizers. Buy
and read the following paper:

http://www.computer.org/concurrency/pd2000/p4072abs.htm
("C++ Exception Handling", Christophe de Dinechin,
 IEEE Concurrency October-December 2000 (Vol. 8, No. 4))

<abstract>
The C++ programming language offers a feature known as exception
handling, which is used, for instance, to report error conditions.
This technique can result in more robust software. On the other
hand, it generally has a highly negative performance impact, even
when exceptions are not actually thrown. This impact is especially
important on an architecture such as the HP/Intel IA-64 processor,
which is very sensitive to compiler optimizations. Hewlett-Packard
implemented exception handling for IA-64 in a way that leaves the
door open for optimizations, even in the presence of exceptions.
</abstract>

regards,
alexander.

The "right" approach is this:

http://groups.google.com/groups?threadm=3EBA6888.D4DF2AB1%40web.de
(Subject: Re: __attribute__((cleanup(function)) versus try/finally)

"....
 The current C++ standard says:

 "The process of calling destructors for automatic objects
  constructed on the path from a try block to a throw-expression
  is called 'stack unwinding.'"

 That's okay (there's a nice definition of 'try-block' as well).

 Now, the current C++ standard also has a couple of kinda-relevant
 "implementation-defined" bits:

  a) "If no matching handler is found in a program, the function
      terminate() is called; whether or not the stack is unwound
      before this call to terminate() is implementation-defined",

  b) "In the situation where no matching handler is found, it is
      implementation-defined whether or not the stack is unwound
      before terminate() is called.".

 and it also defines the semantics of exception specifications...
 in effect, as just a bunch of noop/rethrowing function-try-block
 catch-handlers with a trailing catch(...)-thing that invokes
 std::unexpected().

 I just hate that. To begin with, the definition of the term
 'stack unwinding' makes me wonder what "try-block" is meant
 here:

    int main() {
      object o; // <-- 'unwinding' is implementation-defined
      throw "trouble";
    }

    and here:

    void Main() throw() {
      object o; // <-- 'unwinding' is REQUIRED here
      throw "trouble";
    }

 I believe that in both cases above, std::unexpected() shall
 be invoked as the result of successful evaluating of throw-
 expression and without any 'unwinding' taking place. Further,
 I believe that ALL dtors shall have an implicit throw()-
 nothing exception-spec imposed on them. Finally, I believe
 that the standard should say that 'execution of each and
 every thread' [initial/main including] shall be done "as if"

   whatever run(...whatever...) throw(std::thread_exit,
                                      std::thread_cancel);

 is called; that implementation simply does finalization
 of thread_exit or thread_cancel exception (if thrown)
 resulting in thread termination and that any other uncaught
 exception will end up in std::unexpected() invoked at throw
 point.
 ...."
</-------- Original Message -------->

C) http://google.com/groups?selm=3C91397A.9FC5F5A4%40web.de
   (Subject: Re: C++ and threads)

<quote>

"The process of calling destructors for automatic
 objects constructed on the path from a try block
 to a throw-expression is called 'stack unwinding.'"

 > In the original DCE exception package, which was a set of
 > C macros (over setjmp/longjmp),

 OK, you probably mean something along the lines of:

 ftp://ftp.opengroup.org/pub/dce122/dce/src/threads.tar.gz

 "exc handling.h    46591 05/10/96 14:35
  exc handling.c    37966 05/10/96 14:35"

 > any frame with a TRY/CATCH would unwind even if it had no
 > interest in the exception being propagated. That is, it had
 > to unwind just to find out.

 Question:

 Are you saying that it is practically impossible (or perhaps
 just pointless/silly) to try to "arrange" the C-macros/
 jmp-based exception handling such that when the control
 enters the try block/scope you have already "registered"
 the "identity" of catch{ all} handlers in the "try context
 block" structure as well... so that it could be easily
 checked (i.e the presence of next matching handler
 somewhere on the "stack") at *throw/re-throw* point(s),
 PRIOR to "unwinding"/longjmp-ing to the next frame?

</quote>

Now, what am I missing and/or misunderstanding? TIA.

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]