Topic: Exceptions and longjmp and C


Author: daniel@lia.com (Daniel Edelson)
Date: Fri, 28 Jan 1994 19:18:25 GMT
Raw View
Bob Fraley wrote:

 } What I've heard in the longjmp/exceptions discussion (biased in the
 } process):

 } *  Implementations are allowed to call destructors or not the way the
 }    current standard is written, reducing source portability.  They are
 }    not likely to call destructors, however, as the established norm.

Your statement would be true of "unspecified behavior", or
"implementation-defined behavior".  Longjmping over destructable
objects is "undefined behavior", therefore AN ERROR. This is an error
that the compiler is not required to diagnose. Such code is
UNPORTABLE. There are no constraints on what the generated code may do
so a core dump or an power-supply fire are perfectly acceptable
results of such a longjmp.

Daniel Edelson
daniel@lia.com
IA Corporation





Author: fraley@nsa.hp.com (Bob Fraley)
Date: Tue, 25 Jan 1994 02:12:18 GMT
Raw View
What I've heard in the longjmp/exceptions discussion (biased in the
process):

*  C++ pre-exceptions did not call destructors on longjmp.

*  No change was made to this status, even though the addition of
   exceptions made a reasonable implementation possible.

*  Implementations are allowed to call destructors or not the way the
   current standard is written, reducing source portability.  They are
   not likely to call destructors, however, as the established norm.

*  C++ may not be intermixed with existing C code which does longjmps,
   even though C++ is the "next C" and the inter-operation with Cis
   one of the things which has made it popular.

*  There seems to be some support for the concept that an exception
   mechanism common to C and C++ be specified, such as:

   -  an exception procedure, working like longjmp but calling
      destructors

   -  a set of exception macros which may be used in C and
      interoperate with the C++ exception mechanism


"Fixing" longjmp to work the way that it "should" work with C++ is by
far the most appealing.  Simple uses of longjmp in existing C code
would then work properly with C++, even though some specialized
applications would break.  [A variant of setjmp or longjmp could be
used to indicate the non-destructor version; I don't suppose this was
discussed in the debate.]

We are now left with a broken language.  Is there any hope that the
C++ standards committee would consider standardizing a new function or
a set of macros that would provide common exception mechanisms for C
and C++?  [This would be a C feature, outside their domain, but needed
to fix a problem caused by C++.]  Any hope that they would re-consider
the longjmp decision?

Thanks.

Bob Fraley






Author: kanze@us-es.sel.de (James Kanze)
Date: 25 Jan 1994 19:30:18 GMT
Raw View
In article <2hn2rsINNa4k@early-bird.think.com> chase@Think.COM (David
Chase) writes:

|> There, I tried to be as diplomatic as possible.  In general, I think
|> that you are right, and that longjmp (or something like it, that could
|> be easily substituted for it) should run those destructors.

Something like it, that can be easily substituted for it, does run
those destructors.  It's called an exception.
--
James Kanze                             email: kanze@us-es.sel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                   -- Beratung in industrieller Datenverarbeitung




Author: lmiller@aerospace.aero.org (Lawrence H. Miller)
Date: 26 Jan 1994 19:04:14 GMT
Raw View
In article you write:
>
>...Indeed, it is not legal
>even in C for a signal handler to call longjmp, though it is certainly
>true that some C and C++ implementations permit it in practice.

 Hmmm.  My reading of Section 4.6.2.1 starting at line 15
 (page 120) is that it is only illegal (undefined behavior)
 if longjmp is invoked from "a nested signal handler..."  So
 a fairly stereotypical use of longjmp to get back to a
 known state from a handler seems valid.  Am I missing something?


Larry Miller  The Aerospace Corporation
lmiller@aero.org PO Box 92957
310-336-5597  LA, CA 90009-2957




Author: chase@Think.COM (David Chase)
Date: 20 Jan 1994 23:07:40 GMT
Raw View
> Summary: Why, oh why doesn't the standard make longjmp call destructors?

I'm not sure.  I can think of several reasons.

Number one is that some people think that longjmp means "get me out of
here, things are really wedged" in which case the stack is regarded as
being probably (locally) trashed, so stack walking (for running of
destructors) is regarded as not reliable.

Number two is that longjmp can be called from a signal handler
(asynchronously) which doesn't always mesh well with constructors and
destructors (what if the exception is raised part way through a
constructor -- what destructor is run?)

Number three is that it is easier for the implementor if this is left
unspecified.  I think that standards committees often err on the side of
"too easy", but then I am one of those implementors, so that (a) lifetime
employment sounds great to me and (b) it often looks easier to me than it
does to a non-implementor (of course, sometimes it looks harder.  In this
case, it looks easier).

Number four is that some people engage in the vile, evil practice of using
setjmp/longjmp to implement coroutines in C, and attempting to stack walk
in that situation would be a poor idea.  I think this is a shame, because
one must write a little machine-dependent code to get started on another
stack in the first place, so one might as well write the machine-dependent
code to get you from one to the other.

There, I tried to be as diplomatic as possible.  In general, I think
that you are right, and that longjmp (or something like it, that could
be easily substituted for it) should run those destructors.

David Chase, speaking for myself
Thinking Machines Corporation




Author: jss@lucid.com (Jerry Schwarz)
Date: 21 Jan 1994 00:14:25 GMT
Raw View
In article <CJwKID.K0E@nsa.hp.com> fraley@nsa.hp.com (Bob Fraley) writes:


>   Why does the C++ standard not specify that longjmp call destructors
>   for any stackframes which it deletes?
>

In nutshell, because it doesn't now and we didn't want to change its
current behavior.  I've seen packages that uses longjmps to simulate
exceptions.  This code carefully keeps track of what will need to be
destructed and does it before it calls longjmp.  If longjmp then
destructed stack variables again this code would break.

>   Now that the complaint is out, here is my problem.  I have a large
>   amount of C code which uses a set of macros (shipped with OSF's DCE
>   environment) which implement an exception mechanism in C.  The macros
>   TRY, CATCH, RAISE, FINALLY, and ENDTRY work much like C++ exceptions.
>   [They actually have a nice feature not included in C++.  The FINALLY
>   clause allows the coding of clean-up actions which may be done whether
>   exit is normal or a result of a RAISE.  But that's another story.]
>   These macros are implemented using setjmp and longjmp.
>
>   Now, if I try to add some C++ code into this environment, my
>   destructors don't get called, which is not nice for software which
>   needs to recover and continue execution.  Memory leaks and all that!
>
>
>   The only solution that's practical is to have an implementation of
>   longjmp which calls C++ destructors.  Well, there is another solution:
>   have the macros simulate C++ exceptions and call the destructors
>   themselves.  But this solution makes the macros dependent on a
>   specific C++ compiler version.  That makes high maintenance costs for
>   supporting the macros.

The solution I always envisioned for this is that in an environment
that supports exceptions you replace these macros by ones that
expand to code that uses exceptions.

  -- Jerry Schwarz(jss@lucid.com)












Author: jss@lucid.com (Jerry Schwarz)
Date: 22 Jan 1994 02:05:35 GMT
Raw View
In article <2hn2rsINNa4k@early-bird.think.com> chase@Think.COM (David Chase) writes:

   > Summary: Why, oh why doesn't the standard make longjmp call destructors?

   I'm not sure.  I can think of several reasons.

   Number one ...

   Number two ...

   Number three ...

   Number four ..

   There, I tried to be as diplomatic as possible.  In general, I think
   that you are right, and that longjmp (or something like it, that could
   be easily substituted for it) should run those destructors.

I've eliminated the wild speculation above.  I was there when the
library working group made the decision (that was later endorsed by
the full committee) and I don't remember any of these four
considerations playing any role.

I've already posted the reason that carried the most weight
(at least with me and I think other committee members).  Namely:
that is what longjmp currently does.  I refer you to my other
posting for more discussion

  -- Jerry Schwarz(jss@lucid.com)







Author: ball@cygany.Eng.Sun.COM (Mike Ball)
Date: 21 Jan 1994 16:53:07 GMT
Raw View
In article 2hn2rsINNa4k@early-bird.think.com, chase@Think.COM (David Chase) writes:
> > Summary: Why, oh why doesn't the standard make longjmp call destructors?
> There, I tried to be as diplomatic as possible.  In general, I think
> that you are right, and that longjmp (or something like it, that could
> be easily substituted for it) should run those destructors.

Perhaps we could give it some sort of mnemonic name, like "exception", then
generalize it so it's more useful.....

-Mike Ball-






Author: ark@tempel.research.att.com (Andrew Koenig)
Date: Fri, 21 Jan 1994 15:33:58 GMT
Raw View
In article <2hn2rsINNa4k@early-bird.think.com> chase@Think.COM (David Chase) writes:

> Number one is that some people think that longjmp means "get me out of
> here, things are really wedged" in which case the stack is regarded as
> being probably (locally) trashed, so stack walking (for running of
> destructors) is regarded as not reliable.

Nope, the committee didn't raise that argument.

> Number two is that longjmp can be called from a signal handler
> (asynchronously) which doesn't always mesh well with constructors and
> destructors (what if the exception is raised part way through a
> constructor -- what destructor is run?)

The committee didn't raise that argument either.  Indeed, it is not legal
even in C for a signal handler to call longjmp, though it is certainly
true that some C and C++ implementations permit it in practice.

> Number three is that it is easier for the implementor if this is left
> unspecified.

Bingo!  In general, people felt that once the language has exceptions,
there is no real need for longjmp except for C compatibility.  Why not
allow C++ implementations the option of simply using the one from the local
C library?  That would work only for C++ programs that are no more
than transliterated C programs, but that would be good enough.

> Number four is that some people engage in the vile, evil practice of using
> setjmp/longjmp to implement coroutines in C, and attempting to stack walk
> in that situation would be a poor idea.  I think this is a shame, because
> one must write a little machine-dependent code to get started on another
> stack in the first place, so one might as well write the machine-dependent
> code to get you from one to the other.

The committee didn't talk about that on either.  I do agree with you
on that score, though.

> There, I tried to be as diplomatic as possible.  In general, I think
> that you are right, and that longjmp (or something like it, that could
> be easily substituted for it) should run those destructors.

I agree with you.  My argument, which the committee did not buy, was that
in order to implement exceptions, it is necessary for the implementation to
have some way of unwinding the stack.  It is therefore a trivial extra
bit of work to make that facility explicitly available to users in the form
of setjmp/longjmp.  A number of prople actually agreed with me, and then
*still* voted against making setjmp/longjmp respect destructors.  Purists.

Oh well, one of the side effects of voting is that one doesn't always
like the outcome.
--
    --Andrew Koenig
      ark@research.att.com




Author: ark@tempel.research.att.com (Andrew Koenig)
Date: Thu, 20 Jan 1994 14:56:37 GMT
Raw View
In article <CJwKID.K0E@nsa.hp.com> fraley@nsa.hp.com (Bob Fraley) writes:

> Why does the C++ standard not specify that longjmp call destructors
> for any stackframes which it deletes?

Because the proposal didn't get enough votes to pass.  It *was* discussed.
--
    --Andrew Koenig
      ark@research.att.com




Author: fraley@nsa.hp.com (Bob Fraley)
Date: Thu, 20 Jan 1994 00:39:49 GMT
Raw View
Why does the C++ standard not specify that longjmp call destructors
for any stackframes which it deletes?

Neither of the two C++ compilers I've used which support exceptions
call destructors when they destroy stack frames.  Because they support
exceptions, the information about destructors must be available.  Why
not require that those destructors be called?

The standard states:  If any automatic objects would have been
destroyed due to an exceptiontransferring control to the same function
as the longjmp, the results of longjmp are undefined.

Why not change this to call the destructors which would have been
called?

Now that the complaint is out, here is my problem.  I have a large
amount of C code which uses a set of macros (shipped with OSF's DCE
environment) which implement an exception mechanism in C.  The macros
TRY, CATCH, RAISE, FINALLY, and ENDTRY work much like C++ exceptions.
[They actually have a nice feature not included in C++.  The FINALLY
clause allows the coding of clean-up actions which may be done whether
exit is normal or a result of a RAISE.  But that's another story.]
These macros are implemented using setjmp and longjmp.

Now, if I try to add some C++ code into this environment, my
destructors don't get called, which is not nice for software which
needs to recover and continue execution.  Memory leaks and all that!


The only solution that's practical is to have an implementation of
longjmp which calls C++ destructors.  Well, there is another solution:
have the macros simulate C++ exceptions and call the destructors
themselves.  But this solution makes the macros dependent on a
specific C++ compiler version.  That makes high maintenance costs for
supporting the macros.

So, suggestions on a common exception mechanism for C and C++ would
also be appreciated.

Bob Fraley
Hewlett-Packard