Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why is setjmp a macro?

234 views
Skip to first unread message

t...@cs.ucr.edu

unread,
Aug 26, 2002, 9:08:36 AM8/26/02
to
The specifications for the setjmp macro involves some tedious
provisions that (I presume) would not be present if it were a
function, namely:
- the restrictions on the use of its value,
- the indeterminacy of the non-volatile locals of it caller
under certain circumstances.
So, why not make setjmp a function, especially now that the
function could be inline?

Tom Payne

Douglas A. Gwyn

unread,
Aug 26, 2002, 5:44:02 PM8/26/02
to
t...@cs.ucr.edu wrote:
> So, why not make setjmp a function, ...

Because its semantics are different from those of any function.

t...@cs.ucr.edu

unread,
Aug 26, 2002, 9:08:53 PM8/26/02
to
Douglas A. Gwyn <DAG...@null.net> wrote:

: t...@cs.ucr.edu wrote:
:> So, why not make setjmp a function, ...

: Because its semantics are different from those of any function.

Ah yes, "different semantics". I should have thought of that. ;-)

So, why have semantics been selected that disallow:

int mysetjmp( jup_buf env ) { return setjmp(env); }

Tom Payne

t...@cs.ucr.edu

unread,
Aug 27, 2002, 5:58:12 AM8/27/02
to
t...@cs.ucr.edu wrote:

: Douglas A. Gwyn <DAG...@null.net> wrote:
: : t...@cs.ucr.edu wrote:
: :> So, why not make setjmp a function, ...

: : Because its semantics are different from those of any function.

: Ah yes, "different semantics". I should have thought of that. ;-)

: So, why have semantics been selected that disallow:

^^^^ ^^^^^^^^
Oops: has disallows

: int mysetjmp( jup_buf env ) { return setjmp(env); }

... which forces us to write such nonsense as:

int mysetjmp( jup_buf env ) {

switch( setjmp(env) ) {
case -3: return -3;
case -2: return -2;
case -1: return -1;
case 0: return 0;
case 1: return 1;
case 2: return 2;
case 3: return 3;
default: assert(0); /* unxpected value */
}
}

Tom Payne

David Butenhof

unread,
Aug 27, 2002, 8:26:12 AM8/27/02
to
t...@cs.ucr.edu wrote:

If you think about it, on most machines what setjmp() needs to do is
substantially "unusual". You need to save a machine context (register set)
that can be restored later, allowing the machine to continue from that
context.

So, if setjmp() is a routine, you need to save not the CURRENT machine
context (PC, SP, etc.) but rather the CALLER'S context. Otherwise longjmp()
would be setting the SP to a stack frame (setjmp's) that no longer exists
and may very well have been overwritten by intervening activity! On some
machines setjmp() can be a lightweight no-frame routine the context of
which IS (or is indistinguishable from) the context of its caller... but
there's no way the standard could require that, because it's not possible
on many machines.

When you write a mysetjmp() wrapper, you're extending that problem: you need
to save the context of mysetjmp()'s caller. Now, a custom-written assembly
code setjmp() implementation can easily enough save its caller's context:
but there's no way it can know whether it needs to unwind the stack yet
another frame.

So setjmp() can only work if it knows precisely what context to save; and
that has to be based strictly on machine architecture and knowledge of how
setjmp() itself is built. Any specification that required it to know any
more would be unimplementable. Therefore, it must be specified "as if it
were a macro" so that it's clear what context is saved. (The frame that
invokes setjmp().)

It may actually BE implemented as a macro or compiler intrinsic that saves
the current frame, or as a custom routine that saves its caller's context;
but it would be "highly impractical" to make your wrapper work correctly
and portably, so there's no point in pretending it could be done. (Note
that it COULD be done if the compiler analyzed mysetjmp() to determine that
it did nothing but call setjmp() and return. However, what's the point? And
what about another myothersetjmp(), perhaps in another source file, that
calls mysetjmp()? Should that work, too? Etc.? This is one of those cases
where the best place to stop is before you start. ;-) )

--
/--------------------[ David.B...@hp.com ]--------------------\
| Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\-------------[ http://homepage.mac.com/~dbutenhof ]--------------/

P.J. Plauger

unread,
Aug 27, 2002, 8:20:28 AM8/27/02
to
<t...@cs.ucr.edu> wrote in message news:akfifk$rfi$1...@glue.ucr.edu...

> : :> So, why not make setjmp a function, ...
>
> : : Because its semantics are different from those of any function.
>
> : Ah yes, "different semantics". I should have thought of that. ;-)
>
> : So, why have semantics been selected that disallow:
> ^^^^ ^^^^^^^^
> Oops: has disallows
>
> : int mysetjmp( jup_buf env ) { return setjmp(env); }
>
> ... which forces us to write such nonsense as:
>
> int mysetjmp( jup_buf env ) {
> switch( setjmp(env) ) {
> case -3: return -3;
> case -2: return -2;
> case -1: return -1;
> case 0: return 0;
> case 1: return 1;
> case 2: return 2;
> case 3: return 3;
> default: assert(0); /* unxpected value */
> }

The simple answer is that I reported to the C committee the
various problems I had encountered implementing a C compiler
and setjmp/longjmp for the DEC PDP-11, MC68000, Intel 8086,
Intel 8080, IBM S/370, and DEC VAX. I described the contstraints
on setjmp expressions that would steer clear of the stack and
register management problems I knew of in generating code for
this assortment of machines. The committee accepted these
constraints as not unreasonable, particularly given the other
problems already raised by other compiler writers w.r.t. the
tracking of auto/register variables on setjmp/longjmp calls.

I don't pretend to be the smartest compiler writer in the
world, but I still have sympathy for those who continue to
port Standard C to tiny chips that can barely handle the
language. I personally don't consider the constraints on
setjmp all that onerous, particularly given the intrinsic
dangers inherent in using setjmp/longjmp.

YMMV.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

Lawrence Rust

unread,
Aug 27, 2002, 9:16:16 AM8/27/02
to
<t...@cs.ucr.edu> wrote...

> t...@cs.ucr.edu wrote:
> : Douglas A. Gwyn <DAG...@null.net> wrote:
> : : t...@cs.ucr.edu wrote:
> : :> So, why not make setjmp a function, ...
>
> : : Because its semantics are different from those of any function.
>
> : Ah yes, "different semantics". I should have thought of that. ;-)

At the very least for compatibility with C++. Macros in C++ exist in the
global namespace whereas a setjmp function defined in csetjmp would exist in
the std namespace.

Even if setjmp were a function (as it is in many implementations - #define
setjmp _setjmp) the restrictions would still exist in order to protect the
programmer from UB.

The restrictions prevent a compiler from optimising away a local variable.
For instance:

int i = 0, j = setjmp( buf);
if ( 0 == j)
{
i = j - 1;
... /* expressions only in j */
}
else
{
... /* expressions only in i */
}

mylongjmp( buf); /* This invokes a longjmp */

This code currently invokes UB because the compiler may spot that i and j
are never used simultaneously and so may combine them into one variable.
When setjmp is first called j == 0 and hence the first block is entered
which sets i = -1, this also sets j to -1. When longjmp returns, j will be
set to say 1 which will also overwrite the previously calculated value of i.


> : So, why have semantics been selected that disallow:
> ^^^^ ^^^^^^^^
> Oops: has disallows
>
> : int mysetjmp( jup_buf env ) { return setjmp(env); }
>
> ... which forces us to write such nonsense as:
>
> int mysetjmp( jup_buf env ) {
> switch( setjmp(env) ) {
> case -3: return -3;
> case -2: return -2;
> case -1: return -1;
> case 0: return 0;
> case 1: return 1;
> case 2: return 2;
> case 3: return 3;
> default: assert(0); /* unxpected value */
> }
> }

This function also invokes UB because the function that calls setjmp must
not return before longjmp is called (7.13.2.1.2). On systems with a return
address stack the return address could be modified by code following the
return from mysetjmp. Then when longjmp passes control to the point where
setjmp was called the return address from mysetjmp is invalid.

-- Lawrence Rust, Software Systems, www.softsystem.co.uk
The problem with Windows XP: http://www.arachnoid.com/boycott


t...@cs.ucr.edu

unread,
Aug 27, 2002, 9:22:41 AM8/27/02
to
David Butenhof <David.B...@compaq.com> wrote:
: t...@cs.ucr.edu wrote:
[...]
:> So, why have semantics been selected that disallow:

:>
:> int mysetjmp( jup_buf env ) { return setjmp(env); }

[...]
: When you write a mysetjmp() wrapper, you're extending that problem: you need

: to save the context of mysetjmp()'s caller. Now, a custom-written assembly
: code setjmp() implementation can easily enough save its caller's context:
: but there's no way it can know whether it needs to unwind the stack yet
: another frame.

Oops. Right -- a wrapper would return immediately, so a longjmp would
yield undefined behavior. The puzzling part is why the value of
setjmp can drive a switch statement but can't initialize a variable.
For example, why does

int x = setjmp(env);

cause trouble and have to be "undefined"?

Tom Payne


t...@cs.ucr.edu

unread,
Aug 27, 2002, 9:52:27 AM8/27/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: <t...@cs.ucr.edu> wrote...

:> t...@cs.ucr.edu wrote:
:> : Douglas A. Gwyn <DAG...@null.net> wrote:
:> : : t...@cs.ucr.edu wrote:
:> : :> So, why not make setjmp a function, ...
:>
:> : : Because its semantics are different from those of any function.
:>
:> : Ah yes, "different semantics". I should have thought of that. ;-)

: At the very least for compatibility with C++. Macros in C++ exist in the
: global namespace whereas a setjmp function defined in csetjmp would exist in
: the std namespace.

: Even if setjmp were a function (as it is in many implementations - #define
: setjmp _setjmp) the restrictions would still exist in order to protect the
: programmer from UB.

: The restrictions prevent a compiler from optimising away a local variable.
: For instance:

[...]
: This code currently invokes UB because the compiler may spot that i and j


: are never used simultaneously and so may combine them into one variable.
: When setjmp is first called j == 0 and hence the first block is entered
: which sets i = -1, this also sets j to -1. When longjmp returns, j will be
: set to say 1 which will also overwrite the previously calculated value of i.

Thanks. I had erroneously assumed that this restriction has something
to do with the fact that setjmp is a macro and that there must be
compelling technical reasons not to use a function.

Tom Payne

Douglas A. Gwyn

unread,
Aug 27, 2002, 12:53:58 PM8/27/02
to
t...@cs.ucr.edu wrote:
> ... which forces us to write such nonsense as:
> int mysetjmp( jup_buf env ) {
> switch( setjmp(env) ) {
> case -3: return -3;
> case -2: return -2;
> case -1: return -1;
> case 0: return 0;
> case 1: return 1;
> case 2: return 2;
> case 3: return 3;
> default: assert(0); /* unxpected value */
> }
> }

I agree that is nonsense, but I don't agree that you're forced
to write it.

Douglas A. Gwyn

unread,
Aug 27, 2002, 1:01:52 PM8/27/02
to
"P.J. Plauger" wrote:
> The simple answer is that I reported to the C committee the
> various problems I had encountered implementing a C compiler
> and setjmp/longjmp ...

Also, I volunteered to act as point-of-contact for other compiler
implementors on this issue, as well as the question of what would
be required for a jmp_buf. I heard from several who needed the
kind of specification we ended up with.

But that doesn't really directly address the question why setjmp
is not specified as a function. There are two main reasons for
that aspect: (1) implementations sometimes need special compiler
hooks and an actual function linkage will prevent proper
implementation of setjmp whereas a #define as an intrinsic can
get the job done right; (2) C functions have semantics that are
not obeyed by setjmp, and we don't want to change the semantics
for functions in general -- a "function" that doesn't act as a
function is required to, should be called something else, and
"macro" is appropriate in this context.

Basically, we knew what we were doing...

Douglas A. Gwyn

unread,
Aug 27, 2002, 1:05:52 PM8/27/02
to
t...@cs.ucr.edu wrote:
> ... The puzzling part is why the value of setjmp can drive

> a switch statement but can't initialize a variable.

It has to do with caching values. The constraints ensure that
setjmp/longjmp doesn't have a harder time than it needs to.

t...@cs.ucr.edu

unread,
Aug 27, 2002, 6:38:06 PM8/27/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: <t...@cs.ucr.edu> wrote...

Unfortunately this example doesn't make the point for a couple of reasons:

* i doesn't have a volatile qualified type and is modified after the
invocation of setjmp. Therefore, i has indeterminate type following
a the longjmp and any subsequent use of i yields undefined behavior.

* i and j are both live immediately after the call to setjmp so they
cannot be allocated to the same register.

However, your example can be fixed. Let's simply delete the
assignment to i and suppose that the value of i is held in a register
that gets spilled to a local temp of mylongjmp before longjmp gets
invoked. Now neither setjmp nor longjmp will now be able to find the
proper value of i without groping though the stack in very tedious and
inefficient ways.

Tom Payne


Lawrence Rust

unread,
Aug 28, 2002, 6:57:01 AM8/28/02
to
<t...@cs.ucr.edu> wrote...
> Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
[snip]

> : The restrictions prevent a compiler from optimising away a local
variable.
> : For instance:
>
> : int i = 0, j = setjmp( buf);
> : if ( 0 == j)
> : {
> : i = j - 1;
> : ... /* expressions only in j */
> : }
> : else
> : {
> : ... /* expressions only in i */
> : }
>
> : mylongjmp( buf); /* This invokes a longjmp */
>
> : This code currently invokes UB because the compiler may spot that i and
j
> : are never used simultaneously and so may combine them into one variable.
> : When setjmp is first called j == 0 and hence the first block is entered
> : which sets i = -1, this also sets j to -1. When longjmp returns, j will
be
> : set to say 1 which will also overwrite the previously calculated value
of i.
>
> Unfortunately this example doesn't make the point for a couple of reasons:
>
> * i doesn't have a volatile qualified type and is modified after the
> invocation of setjmp. Therefore, i has indeterminate type following
> a the longjmp and any subsequent use of i yields undefined behavior.

The example was intended to demonstrate exactly why all those restrictions
are in place, not just the restriction on the use of the value returned by
setjmp.


> * i and j are both live immediately after the call to setjmp so they
> cannot be allocated to the same register.

'i' is initially assigned an integral constant so a good optimiser would
replace references to 'i' by the constant up until a new value was computed
at runtime. A good optimiser could then determine that i and j are never
used simultaneously and hence place them in the same register.


> However, your example can be fixed. Let's simply delete the
> assignment to i and suppose that the value of i is held in a register
> that gets spilled to a local temp of mylongjmp before longjmp gets
> invoked. Now neither setjmp nor longjmp will now be able to find the
> proper value of i without groping though the stack in very tedious and
> inefficient ways.

Yes, that's a perfect example of why volatile is needed.

David Butenhof

unread,
Aug 28, 2002, 7:26:13 AM8/28/02
to
Douglas A. Gwyn wrote:

Hmm. Somehow, that sounds like it ought to make sense, but doesn't, quite.
It does have to return the specified values. Once they're returned, why are
there restrictions on what the caller can do with them?

It must be because setjmp() returns TWICE, with different values. When you
use it immediately in a switch(), or if(), the returned value is a
transient temporary; used immediately and forgotten.

When you REMEMBER that value, you're remembering two different values, one
for each return. Confusing, I suppose, potentially. But why "undefined"?

There's a trivial "surface contradiction" here if the variable into which
the value is stored is volatile, since it's defined to remain the same on
the return from longjmp(). But that doesn't really mean anything because
the caller is in this case deliberately OVERWRITING the original value;
it's not happening implicitly. If the variable is an automatic, the value
on longjmp()-ed return is undefined anyway... and, again, you're writing a
new value deliberately and explicitly AFTER return.

So, OK: I don't understand this restriction. Can someone explain it?

Or is it, perhaps, exactly that: that nobody on the committee wanted to try
to explain what it meant? ;-)

Alexander Terekhov

unread,
Aug 28, 2002, 9:33:58 AM8/28/02
to
<repost, DR-014 stuff added>

t...@cs.ucr.edu wrote:

[...Why is setjmp a macro?...]

http://www.opengroup.org/sophocles/show_mail.tpl?source=L&listname=austin-group-l&id=1640

<quote>

Subject: ERN 239 - setjmp

I was asked to query the C Standards committee on the meaning of
"the setjmp macro". In particular, does it allow for setjmp
being a function?

I got several responses. The main one is this question was
asked a long time ago and responded to in Defect Report (DR)
014 against C89. The term "setjmp macro" is used for brevity,
as a shorthand for "the setjmp macro or function (whatever the
identifier 'setjmp' is defined as by the <setjmp.h> header, be
it an actual macro or a function name)".

In addition, we wanted to ensure that no one ever takes the
address of 'setjmp' and then calls it through a pointer to
function. This is done since the address of a macro cannot
be taken.

</quote>

http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/defect-reports.tar.gz

<quote>

Defect Report #014
Submission Date: 10 Dec 92
Submittor: WG14
Source: X3J11/90-049 (Max K. Goff)
Question 1
X/Open Reference Number KRT3.159.1

There are conflicting descriptions of the setjmp() interface in ISO
9899:1990. In subclause 7.6 on page 118, line 8, it is stated that
``It is unspecified whether setjmp is a macro or an identifier
declared with external linkage.'' Throughout the rest of the standard,
however, it is referred to as ``the setjmp macro''; in addition, the
rationale document states that setjmp must be implemented as a macro.
Please clarify whether setjmp must be implemented as a macro, or may
be a function as well as a macro, or may just be a function.

Response

The standard states that setjmp can be either a macro or a function.
It is referred to as ``the setjmp macro'' just to avoid longwindedness.
The rationale document is incorrect in saying that it must be a macro.

</quote>

regards,
alexander.

Alexander Terekhov

unread,
Aug 28, 2002, 9:34:15 AM8/28/02
to
<repost, POSIX.1 "stuff" added>

"Douglas A. Gwyn" wrote:
[...]


> Basically, we knew what we were doing...

In the next round, please:

- deprecate *jmp stuff

- reinvent and introduce try/throw/catch/finally stuff
(consolidated/merged C/C++{/POSIX.1} standard would be
a nice place and opportunity for doing it, I guess ;-) )

TIA.

regards,
alexander.

Lawrence Rust

unread,
Aug 28, 2002, 9:53:14 AM8/28/02
to
"Alexander Terekhov" <tere...@web.de> wrote...

> <repost, POSIX.1 "stuff" added>
>
> "Douglas A. Gwyn" wrote:
> [...]
> > Basically, we knew what we were doing...
>
> In the next round, please:
>
> - deprecate *jmp stuff

This would break any number of co-routine implementations.


> - reinvent and introduce try/throw/catch/finally stuff
> (consolidated/merged C/C++{/POSIX.1} standard would be
> a nice place and opportunity for doing it, I guess ;-) )

Although elegant for certain applications, exceptions add significant
runtime overhead that may deter the use of C in small systems. The *jmp
family is not perfect but is optional and without overhead if not used. If
you need exceptions then you probably need C++.

t...@cs.ucr.edu

unread,
Aug 28, 2002, 10:46:43 AM8/28/02
to
David Butenhof <David.B...@compaq.com> wrote:
: Douglas A. Gwyn wrote:

:> t...@cs.ucr.edu wrote:
:>> ... The puzzling part is why the value of setjmp can drive
:>> a switch statement but can't initialize a variable.
:>
:> It has to do with caching values. The constraints ensure that
:> setjmp/longjmp doesn't have a harder time than it needs to.

[...]
: So, OK: I don't understand this restriction. Can someone explain it?

Consider "int i = setjmp(env);". Perhaps:

address of i gets computed.
address of i gets spilled to a local temp (to make room for setjmp).
setjmp occurs.
address of i gets retrieved to complete the initialization of i.
temp gets reused.
longjmp back to setjmp (after which bogus address of i gets retrieved).

Undefined behavior!

: Or is it, perhaps, exactly that: that nobody on the committee wanted to try

: to explain what it meant? ;-)

Hey, they "did the best they could" and "knew what they were doing".
What else do you need to know? ;-)

Tom Payne

Alexander Terekhov

unread,
Aug 28, 2002, 11:09:09 AM8/28/02
to

Lawrence Rust wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote...
> > <repost, POSIX.1 "stuff" added>
> >
> > "Douglas A. Gwyn" wrote:
> > [...]
> > > Basically, we knew what we were doing...
> >
> > In the next round, please:
> >
> > - deprecate *jmp stuff
>
> This would break any number of co-routine implementations.

Ah, right (to the extent of "breaking" something via labeling
features "deprecated"). Yeah, in the next round, please also:

- incorporate THREADS (posix(*) threads) into C/C++ language
(consolidated/merged C/C++/>>POSIX.1<< standard would be a
nice place and opportunity for doing it, I guess ;-) ;-) )

> > - reinvent and introduce try/throw/catch/finally stuff
> > (consolidated/merged C/C++{/POSIX.1} standard would be
> > a nice place and opportunity for doing it, I guess ;-) )
>
> Although elegant for certain applications, exceptions add significant
> runtime overhead that may deter the use of C in small systems.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Uhmm. Care to elaborate?

> The *jmp
> family is not perfect but is optional and without overhead if not used. If
> you need exceptions then you probably need C++.

Well, you might want to check out the following rather old stuff:

ftp://ftp.opengroup.org/pub/dce122/dce/src/threads.tar.gz
(exc_handling.c, exc_handling.h,... it isn't C++, AFAICS)

regards,
alexander.

(*) Y'know: "memory locations", etc. ;-)

t...@cs.ucr.edu

unread,
Aug 28, 2002, 12:01:00 PM8/28/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: <t...@cs.ucr.edu> wrote...

:> Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: [snip]
:> : The restrictions prevent a compiler from optimising away a local variable.
:> : For instance:
:>
:> : int i = 0, j = setjmp( buf);
:> : if ( 0 == j)
:> : {
:> : i = j - 1;
:> : ... /* expressions only in j */
:> : }
:> : else
:> : {
:> : ... /* expressions only in i */
:> : }
:>
:> : mylongjmp( buf); /* This invokes a longjmp */
:>
:> : This code currently invokes UB because the compiler may spot that i and j
:> : are never used simultaneously and so may combine them into one variable.
:> : When setjmp is first called j == 0 and hence the first block is entered
:> : which sets i = -1, this also sets j to -1. When longjmp returns, j will be
:> : set to say 1 which will also overwrite the previously calculated value of i.
[...]
:> * i and j are both live immediately after the call to setjmp so they

:> cannot be allocated to the same register.

: 'i' is initially assigned an integral constant so a good optimiser would
: replace references to 'i' by the constant up until a new value was computed
: at runtime. A good optimiser could then determine that i and j are never

^^^^^^^^^^
: used simultaneously and hence place them in the same register.

Hmmmm. The compiler cannot presume that the value of i is still zero
after setjmp(buf), so at that point i will need its own location
(possibly a register) distinct from that of j. Right?

:> However, your example can be fixed. Let's simply delete the


:> assignment to i and suppose that the value of i is held in a register
:> that gets spilled to a local temp of mylongjmp before longjmp gets
:> invoked. Now neither setjmp nor longjmp will now be able to find the
:> proper value of i without groping though the stack in very tedious and
:> inefficient ways.

: Yes, that's a perfect example of why volatile is needed.

Oops! I seem to have suffered a spontaneous shift in topics. ;-)

In response to a posting by Dave Butenhof, I gave what I hope is a
correct example of why the value of setjmp(buf) shouldn't be allowed
as an initializer.

Tom Payne

P.J. Plauger

unread,
Aug 28, 2002, 12:36:31 PM8/28/02
to
<t...@cs.ucr.edu> wrote in message news:akinoj$stt$1...@glue.ucr.edu...

> : Or is it, perhaps, exactly that: that nobody on the committee wanted to try
> : to explain what it meant? ;-)
>
> Hey, they "did the best they could" and "knew what they were doing".
> What else do you need to know? ;-)

I need to know why both of you think that adding that little
winky emoticon excuses your being rude and supercilious.

David Butenhof

unread,
Aug 28, 2002, 1:00:31 PM8/28/02
to
t...@cs.ucr.edu wrote:

> David Butenhof <David.B...@compaq.com> wrote:
>
> [...]
> : So, OK: I don't understand this restriction. Can someone explain it?
>
> Consider "int i = setjmp(env);". Perhaps:
>
> address of i gets computed.
> address of i gets spilled to a local temp (to make room for setjmp).
> setjmp occurs.
> address of i gets retrieved to complete the initialization of i.
> temp gets reused.
> longjmp back to setjmp (after which bogus address of i gets retrieved).
>
> Undefined behavior!

Ah. So it's the lifetime of the ADDRESS of 'i' that's the issue, not the
lifetime of the value of 'i'. I think that makes sense. I'll just mark my
curiousity as "satisfied" and leave it at that. Thanks.

Alexander Terekhov

unread,
Aug 28, 2002, 1:16:50 PM8/28/02
to

"P.J. Plauger" wrote:
>
> <t...@cs.ucr.edu> wrote in message news:akinoj$stt$1...@glue.ucr.edu...
>
> > : Or is it, perhaps, exactly that: that nobody on the committee wanted to try
> > : to explain what it meant? ;-)
> >
> > Hey, they "did the best they could" and "knew what they were doing".
> > What else do you need to know? ;-)
>
> I need to know why both of you think that adding that little
> winky emoticon excuses your being rude and supercilious.

I need to know why YOU think that *both of them think* that
adding that little winky emoticon *excuses* whatever you think
of them (i.e. "your being rude and supercilious", whatever). ;-)

regards,
alexander.

David Butenhof

unread,
Aug 28, 2002, 1:24:42 PM8/28/02
to
P.J. Plauger wrote:

> <t...@cs.ucr.edu> wrote in message news:akinoj$stt$1...@glue.ucr.edu...
>
>> : Or is it, perhaps, exactly that: that nobody on the committee wanted to
>> : try to explain what it meant? ;-)
>>
>> Hey, they "did the best they could" and "knew what they were doing".
>> What else do you need to know? ;-)
>
> I need to know why both of you think that adding that little
> winky emoticon excuses your being rude and supercilious.

No "rudeness" was intended. Perhaps the ANSI C committee is a far more pure
and unpolitical arena than POSIX, which is largely the basis of my
standards experience. I can think of several cases where "undefined" really
means that one group insisted it be this way and another group insisted
that it be that way; but both would be satisfied if the standard simply
left them to go their own ways. In several cases the solution was nothing
more than the addition or removal of a few lines of rationale text (which
is officially not even part of the standard).

I can easily imagine such things happening in other standards forums, and
therefore the possibility that some aspects of the standard may have
largely "political" rather than strictly technical explanations. Although
such solutions often aren't strictly in the best interests of the consumers
of the standard, they're also often critical to getting the standard past
balloting, and I accept that as a reality of human nature.(Even while I do
consider it amusing and sometimes frustrating.)

However, if you're going to bother to take offense at such a suggestion, I
gladly apologise.

Lawrence Rust

unread,
Aug 28, 2002, 1:24:22 PM8/28/02
to
<t...@cs.ucr.edu> wrote in message news:akis3s$stt$5...@glue.ucr.edu...

No. The value of i could not normally be changed by a function call since
its address has not taken so it has no aliases by which it could be changed.


> :> However, your example can be fixed. Let's simply delete the
> :> assignment to i and suppose that the value of i is held in a register
> :> that gets spilled to a local temp of mylongjmp before longjmp gets
> :> invoked. Now neither setjmp nor longjmp will now be able to find the
> :> proper value of i without groping though the stack in very tedious and
> :> inefficient ways.
>
> : Yes, that's a perfect example of why volatile is needed.
>
> Oops! I seem to have suffered a spontaneous shift in topics. ;-)
>
> In response to a posting by Dave Butenhof, I gave what I hope is a
> correct example of why the value of setjmp(buf) shouldn't be allowed
> as an initializer.

I believe that your explanation hit the nail on the head.

Lawrence Rust

unread,
Aug 28, 2002, 1:53:51 PM8/28/02
to
"Alexander Terekhov" <tere...@web.de> wrote...
[snip]

> > > - reinvent and introduce try/throw/catch/finally stuff
> > > (consolidated/merged C/C++{/POSIX.1} standard would be
> > > a nice place and opportunity for doing it, I guess ;-) )
> >
> > Although elegant for certain applications, exceptions add significant
> > runtime overhead that may deter the use of C in small systems.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Uhmm. Care to elaborate?

Typically either the compiler maintains an extended back-linked stack frame
or each try block inserts an object into a global list. Either way there's
some runtime overhead, especially stack space.


> > The *jmp
> > family is not perfect but is optional and without overhead if not used.
If
> > you need exceptions then you probably need C++.
>
> Well, you might want to check out the following rather old stuff:
>
> ftp://ftp.opengroup.org/pub/dce122/dce/src/threads.tar.gz
> (exc_handling.c, exc_handling.h,... it isn't C++, AFAICS)

Yes. I've seen and written something like this before with TRY macros
implemented with setjmp. Modern C++ compilers can do much better in
reducing the runtime overhead.

Alexander Terekhov

unread,
Aug 28, 2002, 3:16:06 PM8/28/02
to

Lawrence Rust wrote:
[...]

> Typically either the compiler maintains an extended back-linked stack frame
> or each try block inserts an object into a global list. Either way there's
> some runtime overhead, especially stack space.

Well, on all those archaic *jmp-based EH implementations: certainly! ;-)

> > > The *jmp
> > > family is not perfect but is optional and without overhead if not used.
> If
> > > you need exceptions then you probably need C++.
> >
> > Well, you might want to check out the following rather old stuff:
> >
> > ftp://ftp.opengroup.org/pub/dce122/dce/src/threads.tar.gz
> > (exc_handling.c, exc_handling.h,... it isn't C++, AFAICS)
>
> Yes. I've seen and written something like this before with TRY macros
> implemented with setjmp. Modern C++ compilers can do much better in
> reducing the runtime overhead.

Yep. Here's rather interesting article (10 bucks for non-IEEE-ers) about
sort of modern EH/C++ compilers and "highly negative" performance impact:

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.

P.J. Plauger

unread,
Aug 28, 2002, 4:27:31 PM8/28/02
to
"David Butenhof" <David.B...@compaq.com> wrote in message
news:uH7b9.29$Bv7.4...@news.cpqcorp.net...

> No "rudeness" was intended. Perhaps the ANSI C committee is a far more pure
> and unpolitical arena than POSIX, which is largely the basis of my
> standards experience.

The C committee was far from pure, but it was IME rather less politicized
than many others. And yes, I did participate directly in Posix work for
several years.

> However, if you're going to bother to take offense at such a suggestion, I
> gladly apologise.

Thanks. I was being a bit tetchy, I'll admit.

t...@cs.ucr.edu

unread,
Aug 28, 2002, 4:42:29 PM8/28/02
to
P.J. Plauger <p...@dinkumware.com> wrote:
: <t...@cs.ucr.edu> wrote in message news:akinoj$stt$1...@glue.ucr.edu...

:> : Or is it, perhaps, exactly that: that nobody on the committee wanted to try
:> : to explain what it meant? ;-)
:>
:> Hey, they "did the best they could" and "knew what they were doing".
:> What else do you need to know? ;-)

: I need to know why both of you think that adding that little
: winky emoticon excuses your being rude and supercilious.

IMHO, it's neither inappropriate nor rude to draw attention to some of
the we-had-our-reasons replies in this thread. My tone, however, was
admittedly supercilious, and I apologize for the offense it caused.

FWIW, the best information I've found on the reasons for the
restrictions on using the return value of setjmp is:

setjmp must guess how much "calling context" to store in the jmp_buf
data object. It is a safe bet that certain registers must be saved.
A register that can hold intermediate results across a function call
is a prime candidate, since the longjmp call can be in a called
function. Once the program evaluates setjmp, it needs these
intermediate results to complete evaluation of the expression. If
setjmp fails to save all intermediate results, a subsequent return
stimulated by a longjmp call will misbehave
[The Standard C Library, P.J. Plauger, p 183]

Thanks.

Tom Payne

Francis Glassborow

unread,
Aug 28, 2002, 4:53:42 PM8/28/02
to
In article <uH7b9.29$Bv7.4...@news.cpqcorp.net>, David Butenhof
<David.B...@compaq.com> writes

>No "rudeness" was intended. Perhaps the ANSI C committee is a far more pure
>and unpolitical arena than POSIX, which is largely the basis of my
>standards experience. I can think of several cases where "undefined" really
>means that one group insisted it be this way and another group insisted
>that it be that way; but both would be satisfied if the standard simply
>left them to go their own ways. In several cases the solution was nothing
>more than the addition or removal of a few lines of rationale text (which
>is officially not even part of the standard).

No, in those cases we make it implementation defined. We work hard to
try to reduce cases of undefined behaviour. We have quite a way to go
yet, but we have never done it lightly or AFAIK as a purely political
decision.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Alexander Terekhov

unread,
Aug 28, 2002, 6:09:11 PM8/28/02
to

t...@cs.ucr.edu wrote:
[...]

> FWIW, the best information I've found on the reasons for the
> restrictions on using the return value of setjmp is:
>
> setjmp must guess how much "calling context" to store in the jmp_buf
> data object. It is a safe bet that certain registers must be saved.
> A register that can hold intermediate results across a function call
> is a prime candidate, since the longjmp call can be in a called
> function. Once the program evaluates setjmp, it needs these
> intermediate results to complete evaluation of the expression. If
> setjmp fails to save all intermediate results, a subsequent return
> stimulated by a longjmp call will misbehave
> [The Standard C Library, P.J. Plauger, p 183]

Well, AFAIK, Plauger also wrote this (quote is taken from another usenet
posting):

The C standard legislates the kind of expression that can contain
setjmp as a sub-expression. The idea is to preclude any expression
that might store intermediate results in dynamic storage that is
unknown (and unknowable) to setjmp. Thus you can write forms such
as: switch (setjmp(buf)) ..., if (2 < setjmp(buf)) ...,
if (!setjmp(buf)) ..., and the expression statement setjmp(buf).

You can write no forms more complex than these. Note that you
cannot reliably assign the values of setjmp, as in n=setjmp(buf).
The expression may well evaluate properly, but the C Standard
doesn't require it.

Now, how about this (not that I think that it's MUCH better, but... ;-) ):

http://groups.google.com/groups?selm=946775637snz%40genesis.demon.co.uk
(Subject: Re: help with setjmp/longjmp, From: Lawrence Kirby)

<quote>

There are essentially 3 steps to assignment

1. The left hand lvalue expression is evaluated

2. The right hand value expression is evaluated

3. The value from 2 is converted to the type of the lvalue from 1
and written to the object that the lvalue designates.

Of these steps the only ordering is that 3 depends on the results of
1 and 2 so must come after both. There is no ordering between steps 1
and 2. That means that step 1 can be messed up by the action of the
setjmp()/longjmp() mechanism. Also consider that setjmp() will appear
to return twice, once from the initial setjmp() invocation, and again
from the longjmp() call. There's no requirement from C's normal
expression evaluation semantics that steps 1 and 3 be able to cope with
this, i.e. reentering the evaluation of an expression partway through.
setjmp()/longjmp() is required to make this work for a limited set of
expression forms and contexts but they all avoid assignment and other
potentially unpleasant issues.

</quote>

regards,
alexander.

t...@cs.ucr.edu

unread,
Aug 28, 2002, 8:18:58 PM8/28/02
to
Alexander Terekhov <tere...@web.de> wrote:

[... three explanations for restrictions on use of setjmp's value ...]

To sharpen the focus a bit, suppose a problem occurs when we longjmp
back to an occurrence of "setjmp(...)" within a larger expression or
declaration. Then longjmp must have failed to restore the value of
some previously evaluated subexpression that was stored somewhere. If
longjmp restores all registers, then that subexpression's value must
have been spilled to memory prior to setjmp.

Tom Payne

t...@cs.ucr.edu

unread,
Aug 28, 2002, 10:33:27 PM8/28/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: "Alexander Terekhov" <tere...@web.de> wrote...

: [snip]
:> > > - reinvent and introduce try/throw/catch/finally stuff
:> > > (consolidated/merged C/C++{/POSIX.1} standard would be
:> > > a nice place and opportunity for doing it, I guess ;-) )
:> >
:> > Although elegant for certain applications, exceptions add significant
:> > runtime overhead that may deter the use of C in small systems.
:> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:>
:> Uhmm. Care to elaborate?

: Typically either the compiler maintains an extended back-linked stack frame
: or each try block inserts an object into a global list. Either way there's
: some runtime overhead, especially stack space.

By definition, there'll be overhead when a throw is executed. But,
under the latter approach, there is no overhead if no try blocks get
executed, e.g., if the program is a C program.

Tom Payne


t...@cs.ucr.edu

unread,
Aug 29, 2002, 12:30:06 AM8/29/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
: <t...@cs.ucr.edu> wrote in message news:akis3s$stt$5...@glue.ucr.edu...

:> Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
:> : <t...@cs.ucr.edu> wrote...
:> :> Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
:> : [snip]
:> :> : For instance:

:> :>
:> :> : int i = 0, j = setjmp( buf);
:> :> : if ( 0 == j) {
:> :> : i = j - 1;
:> :> : ... /* expressions only in j */
:> :> : } else {
:> :> : ... /* expressions only in i */
:> :> : }
:> :>
:> :> : mylongjmp( buf); /* This invokes a longjmp */
[...]
:> : 'i' is initially assigned an integral constant so a good optimiser would

:> : replace references to 'i' by the constant up until a new value was computed
:> : at runtime. A good optimiser could then determine that i and j are never
:> : used simultaneously and hence place them in the same register.

:>
:> Hmmmm. The compiler cannot presume that the value of i is still zero
:> after setjmp(buf), so at that point i will need its own location
:> (possibly a register) distinct from that of j. Right?

: No. The value of i could not normally be changed by a function call since
: its address has not taken so it has no aliases by which it could be changed.

Hmmmmmmmmmm. Good point. So, suppose that i has a volatile-qualified
type, since otherwise the behavior following longjmp is undefined.
Then, regardless of what non-zero value the initialization of j leaves
in that register, a fresh copy of j's value will be fetch after the
first sequence point following "else". Right (this time)? ;-)

Tom Payne

t...@cs.ucr.edu

unread,
Aug 29, 2002, 12:41:06 AM8/29/02
to
t...@cs.ucr.edu wrote:

^
Oops! make that i's value

: first sequence point following "else". Right (this time)? ;-)

: Tom Payne

t...@cs.ucr.edu

unread,
Aug 29, 2002, 1:44:05 AM8/29/02
to
David Butenhof <David.B...@compaq.com> wrote:
: t...@cs.ucr.edu wrote:

:> David Butenhof <David.B...@compaq.com> wrote:
:>
:> [...]
:> : So, OK: I don't understand this restriction. Can someone explain it?
:>
:> Consider "int i = setjmp(env);". Perhaps:
:>
:> address of i gets computed.
:> address of i gets spilled to a local temp (to make room for setjmp).
:> setjmp occurs.
:> address of i gets retrieved to complete the initialization of i.
:> temp gets reused.
:> longjmp back to setjmp (after which bogus address of i gets retrieved).
:>
:> Undefined behavior!

: Ah. So it's the lifetime of the ADDRESS of 'i' that's the issue, not the
: lifetime of the value of 'i'. I think that makes sense. I'll just mark my
: curiousity as "satisfied" and leave it at that. Thanks.

Not so much "lifetime" as *place*:

- good: places that get saved by setjmp and restored by longjmp,

- bad: everywhere else, which includes all memory locations,
e.g., temps where spilled registers get saved.

Tom Payne


Douglas A. Gwyn

unread,
Aug 29, 2002, 2:37:58 AM8/29/02
to
Lawrence Rust wrote:
> Although elegant for certain applications, exceptions add significant
> runtime overhead that may deter the use of C in small systems. The
> *jmp family is not perfect but is optional and without overhead if
> not used. If you need exceptions then you probably need C++.

I have to disagree with most of that. Indeed, there have been
several implementations *in Standard C* of exceptions (using macro
definitions etc.) that have no overhead if not used, and about as
low overhead as possible when exceptions are used. There are many
good uses for exceptions in ordinary C programming. I doubt that
we could adopt exactly the C++ style, for somewhat obvious reasons,
but a similar facility could be provided.

Douglas A. Gwyn

unread,
Aug 29, 2002, 2:41:16 AM8/29/02
to
t...@cs.ucr.edu wrote:
> ... Now neither setjmp nor longjmp will now be able to find the

> proper value of i without groping though the stack in very tedious
> and inefficient ways.

Indeed, some of the ancestors of setjmp/longjmp were like that:
the stack had to be unwound etc.

Douglas A. Gwyn

unread,
Aug 29, 2002, 3:37:53 AM8/29/02
to
Francis Glassborow wrote:
> ... We work hard to try to reduce cases of undefined behaviour.

More precisely, unnecessary cases of UB. Many cases are necessary
in order to accommodate the real world of diverse ISAs.

Lawrence Rust

unread,
Aug 29, 2002, 6:01:36 AM8/29/02
to
<t...@cs.ucr.edu> wrote...

Agreed.

Am I right in thinking that this same line of reasoning could allow the
easing of the environmental limitations in 7.13.1.1.4 and permit the result
of setjmp to be safely assigned to a volatile qualified lvalue? The
volatile attribute prevents the compiler from assigning 'i' to a register,
any other optimisations and requires re-evaluation of the lvalue before
assignment occurs. When longjmp returns control the compiler is obliged to
re-evaluate the volatile lvalue and assign it the value from the longjmp.

Lawrence Rust

unread,
Aug 29, 2002, 6:23:31 AM8/29/02
to
"Douglas A. Gwyn" <DAG...@null.net> wrote...

My primary concern are mechanisms that may be required to protect existing
exception agnostic code from resource leaks. C doesn't have destructors to
release resources during exception handling so objects like VLA's or similar
that are not allocated on the stack by the compiler must be linked into some
disposal mechanism.

Alexander Terekhov

unread,
Aug 29, 2002, 6:46:33 AM8/29/02
to

"Douglas A. Gwyn" wrote:
>
> Lawrence Rust wrote:
> > Although elegant for certain applications, exceptions add significant
> > runtime overhead that may deter the use of C in small systems. The
> > *jmp family is not perfect but is optional and without overhead if
> > not used. If you need exceptions then you probably need C++.
>
> I have to disagree with most of that. Indeed, there have been
> several implementations *in Standard C* of exceptions (using macro
> definitions etc.) that have no overhead if not used,

Yep. That's because C doesn't have destructors. (they are all "trivial";
in C++ terms, I guess ;-) ) Well, perhaps this problem could also be
solved using: "compensation code is placed along the exceptional paths
to restore program state before executing the exception handlers to what
it would have been if the optimization had not taken place", with respect
to destructors just like it's done for exception handlers; don't know.

> and about as
> low overhead as possible when exceptions are used. There are many
> good uses for exceptions in ordinary C programming. I doubt that
> we could adopt exactly the C++ style, for somewhat obvious reasons,

Why not? Well, I guess, you'd need "finally" clauses to ``compensate''
the lack of destructors (RAII)... but that's it, AFAICS.

> but a similar facility could be provided.

Nah, everybody-and-his-dog (in their right mind, of course) DESPERATELY
NEED "a similar facility"! ;-) ;-)

regards,
alexander.

Alexander Terekhov

unread,
Aug 29, 2002, 7:04:52 AM8/29/02
to

Lawrence Rust wrote:
[...]

> My primary concern are mechanisms that may be required to protect existing
> exception agnostic code from resource leaks. C doesn't have destructors to
> release resources during exception handling so objects like VLA's ....
^^^^^

Ha! C-VLA's-like resource *acquisition failures* aside for a moment, what
about C-longjmp w.r.t. C-VLA's >>leaks<<? Note that in C++, longjmp is
*severely restricted*:

"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 longjmp( jbuf, val)
at the throw point that transfers control to the same
(destination) point has undefined behavior."

regards,
alexander.

t...@cs.ucr.edu

unread,
Aug 29, 2002, 8:03:18 AM8/29/02
to
Lawrence Rust <l...@nospam.softsystem.co.uk> wrote:
[...]
: Am I right in thinking that this same line of reasoning could allow the

: easing of the environmental limitations in 7.13.1.1.4 and permit the result
: of setjmp to be safely assigned to a volatile qualified lvalue? The
: volatile attribute prevents the compiler from assigning 'i' to a register,
: any other optimisations and requires re-evaluation of the lvalue before
: assignment occurs. When longjmp returns control the compiler is obliged to
: re-evaluate the volatile lvalue and assign it the value from the longjmp.

AFAIK, the volatility of an obect's type imposes an obligation on when
to update the content of the object's memory segment but not on when
to recompute its address, which like any other temporary can be
precomputed, cached, spilled, etc.

Tom Payne

Lawrence Rust

unread,
Aug 29, 2002, 8:05:53 AM8/29/02
to
"Alexander Terekhov" <tere...@web.de> wrote...

>
> Lawrence Rust wrote:
> [...]
> > My primary concern are mechanisms that may be required to protect
existing
> > exception agnostic code from resource leaks. C doesn't have destructors
to
> > release resources during exception handling so objects like VLA's ....
> ^^^^^
>
> Ha! C-VLA's-like resource *acquisition failures* aside for a moment, what
> about C-longjmp w.r.t. C-VLA's >>leaks<<? Note that in C++, longjmp is
> *severely restricted*:

Exactly, when a programmer uses any runtime allocated resource with longjmp
they must take positive action to dispose of it. In some cases this is
achieved by a custom implementation of longjmp. If exceptions are added to
the core C language then the programmer is unable to prevent resource leaks
without major code rewrites i.e. adding catch or finally clauses. It's a
much bigger job than in C++ because there are no destructors.

The compiler can guard against much of this by creating an extended stack
frame which contains information on resources, such as VLAs, to be disposed
of. It's this overhead that may be unacceptable in small systems.

Alexander Terekhov

unread,
Aug 29, 2002, 9:25:08 AM8/29/02
to

Lawrence Rust wrote:
[...]

> Exactly, when a programmer uses any runtime allocated resource with longjmp
> they must take positive action to dispose of it. In some cases this is
> achieved by a custom implementation of longjmp. If exceptions are added to
> the core C language then the programmer is unable to prevent resource leaks
> without major code rewrites i.e. adding catch or finally clauses. It's a
> much bigger job than in C++ because there are no destructors. ....

< IEEE Std (ISO/IEC too) >>pthread_cleanup_push/_pop<< Std-C-"extension"
aside for a moment >

That's true... unless the C standards committee (or, perhaps, the "C core"
working group of a future hypothetical consolidated/merged C/C++/POSIX.1
committee ;-) ) decides to declare that almost-each-and-every C function
(just a few "beasts" from C-STD-LIB aside; see below) WITHOUT explicitly
declared exception specification (ES) shall, in effect, have current-C++-
like[1] throw()-"nix" exception specification... and, BTW, AFAIK, the C++
standards committee have ALREADY legislated and proclaimed that the
standard C{9899:1990,9899/Amd.1:1995} library (a subset of the standard
C++ library) SHALL NOT THROW[2]:

"17.4.4.8 Restrictions on exception handling 17 Library introduction

2 None of the functions from the Standard C library shall report an
error by throwing an exception,176) unless it calls a program-supplied
function that throws an exception.177)
....
176) That is, the C library functions all have a throw() exception-
specification. This allows implementations to make performance
optimizations based on the absence of exceptions at runtime.

177) The functions qsort() and bsearch() (25.4) meet this condition."

regards,
alexander.

[1] But, hopefully, revised&fixed in the next standardization round,
getting rid of rather silly ES's catch(...)-"semantics".

[2] That's really "kinda funny"... given that quite a few *standard*
C library functions HAVE BEEN DECLARED TO BE THREAD CANCELLATION
POINTS BY >>THE POSIX STANDARDS COMMITTEE<<... "LOL" ;-) ;-) ;-)

David Butenhof

unread,
Aug 29, 2002, 9:34:53 AM8/29/02
to
Lawrence Rust wrote:

> "Alexander Terekhov" <tere...@web.de> wrote...
>>
>> Lawrence Rust wrote:
>> [...]
>> > My primary concern are mechanisms that may be required to protect
> existing
>> > exception agnostic code from resource leaks. C doesn't have
>> > destructors
> to
>> > release resources during exception handling so objects like VLA's ....
>> ^^^^^
>> Ha! C-VLA's-like resource *acquisition failures* aside for a moment, what
>> about C-longjmp w.r.t. C-VLA's >>leaks<<? Note that in C++, longjmp is
>> *severely restricted*:
>
> Exactly, when a programmer uses any runtime allocated resource with
> longjmp
> they must take positive action to dispose of it. In some cases this is
> achieved by a custom implementation of longjmp. If exceptions are added
> to the core C language then the programmer is unable to prevent resource
> leaks
> without major code rewrites i.e. adding catch or finally clauses. It's a
> much bigger job than in C++ because there are no destructors.

I don't buy that argument, except in that exceptions are a much nicer model
than setjmp/longjmp and would encourage wider use.

If you write a routine called by someone who did a setjmp(), and are
interrupted by (or call) some routine that does the longjmp(), you have NO
WAY to protect yourself and your resources. (Even given the luxury of "a
custom implementation of longjmp", that's an option only for ONE facility
in a process, whereas exceptions are completely modular.)

If this "unwind" operation was done with an exception, you WOULD have a way
to protect yourself, by introducing an exception handler. Yes, destructors
are better for some things, and far easier to manage since they're implicit
in any data allocation. I don't see how C could get "destructors", but it'd
be worthwhile to think about it. Still, you can get by without them. We've
used exceptions in C for well over a decade, and they solve far more
problems than they cause.

It's true that setjmp/longjmp is "relatively rarely" used because it's
obvious (I think) (to most people) that it's a problem. Whereas if a new
"C2009" standard added exceptions, "everyone" would race to use them, while
it might take the maintainers of those middle frame a long time to catch up
and protect themselves. I can see the validity of such concerns, but it's a
different level of concern than what you seem to be expressing in your
response to Alexander.

Exceptions would provide a clean and portable SOLUTION to the EXISTING
problem. Only in the transition phase will they allow eager developers to
create complication and confusion; and that will tend to correct itself
over time.

Gabriel Dos Reis

unread,
Aug 29, 2002, 10:32:20 AM8/29/02
to David.B...@compaq.com
David Butenhof <David.B...@compaq.com> writes:

| P.J. Plauger wrote:
|
| > <t...@cs.ucr.edu> wrote in message news:akinoj$stt$1...@glue.ucr.edu...
| >
| >> : Or is it, perhaps, exactly that: that nobody on the committee wanted to
| >> : try to explain what it meant? ;-)
| >>
| >> Hey, they "did the best they could" and "knew what they were doing".
| >> What else do you need to know? ;-)
| >
| > I need to know why both of you think that adding that little
| > winky emoticon excuses your being rude and supercilious.
|
| No "rudeness" was intended. Perhaps the ANSI C committee is a far more pure
| and unpolitical arena than POSIX, which is largely the basis of my
| standards experience. I can think of several cases where "undefined" really
| means that one group insisted it be this way and another group insisted
| that it be that way; but both would be satisfied if the standard simply
| left them to go their own ways. In several cases the solution was nothing
| more than the addition or removal of a few lines of rationale text (which
| is officially not even part of the standard).

I don't have experience with the POSIX standard committee, but I
happen to see something along the lines you described in both C and
C++ standards committee -- but, yes, the _technical_ issues are the
majority of the concerns.

-- Gaby

Alexander Terekhov

unread,
Aug 28, 2002, 6:43:55 AM8/28/02
to

"Douglas A. Gwyn" wrote:
[...]
> Basically, we knew what we were doing...

In the next round, please:

- deprecate *jmp stuff

- reinvent and introduce try/throw/catch/finally stuff

(consolidated/merged C/C++ standard would be a nice


place and opportunity for doing it, I guess ;-) )

TIA.

regards,
alexander.

Francis Glassborow

unread,
Aug 31, 2002, 11:53:00 AM8/31/02
to
In article <3D6CA96B...@web.de>, Alexander Terekhov
<tere...@web.de> writes

If you want a proposal like this you will have to put your money where
your mouth is. That means you will need to do the work drafting a
proposal and either find a sponsor or start attending meetings yourself.

And stop day dreaming, a merged C & C++ isn't going to happen, at least
not for a long long (int) time.

What I do not understand is why you want this in C when you already have
it in C++.

Alexander Terekhov

unread,
Aug 31, 2002, 2:20:39 PM8/31/02
to

Francis Glassborow wrote:
[...]

> >In the next round, please:
> >
> > - deprecate *jmp stuff
> >
> > - reinvent and introduce try/throw/catch/finally stuff
> > (consolidated/merged C/C++ standard would be a nice
> > place and opportunity for doing it, I guess ;-) )
>
> If you want a proposal like this you will have to put your money where
> your mouth is. That means you will need to do the work drafting a
> proposal and either find a sponsor or start attending meetings yourself.

I have no time and incentive to start attending meetings myself. I consider
myself "a customer" and just voice my opinions with respect to "the product"
I happen to use. As for sponsoring... how much money (in the range of a few
petabucks, please; let's be realistic) would it cost to "sponsor" the merger,
Francis? ;-)

> And stop day dreaming, a merged C & C++ isn't going to happen,

Well, yeah, I know... ;-) [note that not only "journalists are supposed to
protect their sources", Francis]

----
<private correspondence, a few months ago>

<snip the beginning of the e-mail>

: > > Merging WG14 and WG21 won't fly, for political reasons.
:
: > That's really bad. I really don't understand this.
:
: > > There are too many influential people in WG14 who positively
: > > dislike C++.
:
: > Some Yankees, I guess? ;-)
:
: Actually, I think that the worst offender is a Brit

<snip smiley and the rest of the e-mail>
----

> at least not for a long long (int) time.

"long long (int) time" measured in yocto... or yotta... seconds? C'mon,
The Universe is less than 16 (or so; "<= teenage" so to speak) Gy old.
http://physics.nist.gov/cuu/Units/prefixes.html ;-)

> What I do not understand is why you want this in C when you already
> have it in C++.

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_HTML/ARH9RBTE/DOCU0009.HTM#excep_about_pkg

"....
5.1 About the Exceptions Package

The exceptions package is a part of the POSIX Threads Library. A C language
header file ( pthread_exception.h ) provides an interface for defining and
handling exceptions. It is designed for use with the pthreads interface
routines. If the exceptions package is used, your application must be linked
with the Threads Library.

5.1.1 Supported Programming Languages

The exceptions package can be used only when you are programming in the
C language. While the exceptions will compile under C++, they will not behave
properly. In addition, gcc lacks the Compaq C extensions that are needed to
interact with the native exception handling system, and will not interoperate
correctly with other language exception facilities.

You can use the C language exception handling mechanism (SEH) to catch
exceptions. You can catch exceptions in C++ using catch(...) , and propagation
of exceptions will run C++ object destructors. Currently, C++ code cannot catch
specific exceptions. Also, CATCH , CATCH_ALL and FINALLY clauses will not run
when C++ code raises an exception. (These restrictions will be reduced or
removed in a future release.)

5.1.2 Relation of Exceptions to Return Codes and Signals

The Threads Library uses exceptions in the following cases:

- The pthread_exit() routine raises the exception pthread_exit_e defined by
the Threads Library.

- Canceling a thread causes the Threads Library to raise the exception
pthread_cancel_e defined by the Threads Library.

- On Tru64 UNIX, synchronous signals (such as SIGSEGV) are converted to
exceptions unless a signal action is declared.

...."

regards,
alexander.

Alexander Terekhov

unread,
Aug 31, 2002, 2:56:32 PM8/31/02
to

< forgot one thing; sort of "illustration" >

Alexander Terekhov wrote:
[...]


> > What I do not understand is why you want this in C when you already
> > have it in C++.
>
> http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_HTML/ARH9RBTE/DOCU0009.HTM#excep_about_pkg
>
> "....

> 5.1 About the Exceptions Package ....

----
spe207.testdrive.compaq.com> what /shlib/libpthread.so|grep DECthreads
DECthreads version V3.18-138 May 12 2002
spe207.testdrive.compaq.com> cc -pthread -o seh seh.c
spe207.testdrive.compaq.com> ./seh

Go...

Hi There! Greetings from the ``yellow zone.''

Exception: Attempted stack overflow was detected (dce / thd)

Indeed. ;-)

spe207.testdrive.compaq.com> cat seh.c

#include <stdio.h>
#include <memory.h>
#include <pthread.h>
#include <pthread_exception.h>

void operation()
{
char buffer[128];
memset( buffer, 0, sizeof( buffer ) );
operation();
}

void* my_thread( void* p )
{
TRY {
printf( "\nGo...\n\n" );
operation();
}
CATCH_ALL {
printf( "Hi There! Greetings from the ``yellow zone.''\n\n" );
pthread_exc_report_np( THIS_CATCH );
TRY {
RERAISE;
}
CATCH( pthread_stackovf_e ) {
printf( "\nIndeed. ;-)\n\n" );
} ENDTRY
}
ENDTRY
return NULL;
}

int main()
{
pthread_t tid;
pthread_create( &tid, NULL, &my_thread, NULL );
pthread_exit( NULL );
}

spe207.testdrive.compaq.com> cc -pthread -c -o seh2c.o seh2c.c
spe207.testdrive.compaq.com> cxx -pthread -o seh2 seh2cpp.cpp seh2c.o
spe207.testdrive.compaq.com> ./seh2

C++ try...

Go...

Hi There! Greetings from the ``yellow zone.''

Exception: Attempted stack overflow was detected (dce / thd)

Indeed. ;-) Ha! >>RERAISE<<

C++ catch(...)

Finished!

spe207.testdrive.compaq.com> cat seh2c.c

#include <stdio.h>
#include <memory.h>
#include <pthread.h>
#include <pthread_exception.h>

void operation()
{
char buffer[128];
memset( buffer, 0, sizeof( buffer ) );
operation();
}

void go()
{
TRY {
printf( "\nGo...\n\n" );
operation();
}
CATCH_ALL {
printf( "Hi There! Greetings from the ``yellow zone.''\n\n" );
pthread_exc_report_np( THIS_CATCH );
TRY {
RERAISE;
}
CATCH( pthread_stackovf_e ) {
printf( "\nIndeed. ;-) Ha! >>RERAISE<<\n\n" );
RERAISE;
} ENDTRY
} ENDTRY
}


spe207.testdrive.compaq.com> cat seh2cpp.cpp

#include <pthread.h>

#include <iostream>
using namespace std;

extern "C" void go();

extern "C" void* my_thread( void* p )
{
cout << "\nC++ try..." << endl;
try {
go();
}
catch(...) {
cout << "C++ catch(...)" << endl;
}
cout << "\nFinished!\n" << endl;
return 0;
}

int main()
{
pthread_t tid;
pthread_create( &tid, 0, &my_thread, 0 );
pthread_exit( 0 );
}

spe207.testdrive.compaq.com>
----

regards,
alexander.

James Russell Kuyper Jr.

unread,
Aug 31, 2002, 6:11:04 PM8/31/02
to
Alexander Terekhov wrote:
>
> Francis Glassborow wrote:
...

> > If you want a proposal like this you will have to put your money where
> > your mouth is. That means you will need to do the work drafting a
> > proposal and either find a sponsor or start attending meetings yourself.
>
> I have no time and incentive to start attending meetings myself. I consider
> myself "a customer" and just voice my opinions with respect to "the product"
> I happen to use. As for sponsoring... how much money (in the range of a few
> petabucks, please; let's be realistic) would it cost to "sponsor" the merger,
> Francis? ;-)

I presume he was talking about the proposal, not the merger. As things
stand now, the C standard is precisely for those people who DONT want to
use C++, if they did, they'd worry only about the C++ standard. They
therefore tend to not be interested in adding C++ features to C.

The cost of committee membership depends upon your national committee;
the US committee cost $800/yr. last time I checked, and is open to
membership by people who aren't from the US. Of course, if you can
convince a current member that your proposal is worth supporting, you
don't have to become one yourself, just write it up and give it to them.

Francis Glassborow

unread,
Aug 31, 2002, 6:24:52 PM8/31/02
to
In article <3D7108F7...@web.de>, Alexander Terekhov
<tere...@web.de> writes

><private correspondence, a few months ago>
>
><snip the beginning of the e-mail>
>
>: > > Merging WG14 and WG21 won't fly, for political reasons.
>:
>: > That's really bad. I really don't understand this.
>:
>: > > There are too many influential people in WG14 who positively
>: > > dislike C++.
>:
>: > Some Yankees, I guess? ;-)
>:
>: Actually, I think that the worst offender is a Brit
>
><snip smiley and the rest of the e-mail>

You do know that you are not supposed to quote private correspondence
without agreement don't you?

Alexander Terekhov

unread,
Sep 2, 2002, 7:11:49 AM9/2/02
to

Francis Glassborow wrote:
>
> In article <3D7108F7...@web.de>, Alexander Terekhov
> <tere...@web.de> writes
> ><private correspondence, a few months ago>
[...]

> You do know that you are not supposed to quote private correspondence
> without agreement don't you?

I've made this up, forget it. ;-) ;-)

regards,
alexander.

P.S. Oh, BTW, Francis, don't miss Message-ID: <3D7340B4...@web.de> and
Message-ID: <3D7343D4...@web.de>.... Ariane-V's main on board computer
decided to hit self-destruct button as a consequence of pthread_exc_intovf_e
or so >>EXCEPTION<<... but in ADA. ;-) ;-)

http://groups.google.com/groups?selm=c29b5e33.0202161451.2ef75f1f%40posting.google.com
(Subject: Re: Exception specifications, Newsgroups: comp.lang.c++.moderated)

Alexander Terekhov

unread,
Sep 2, 2002, 1:52:48 PM9/2/02
to

"James Russell Kuyper Jr." wrote:
[...]

> As things
> stand now, the C standard is precisely for those people who DONT want to
> use C++,

But I WANT/NEED to use either C or C++ (more than its C subset)...
depending on the "situation". Is this sort of "exception" or what? ;-)

> if they did, they'd worry only about the C++ standard. They
> therefore tend to not be interested in adding C++ features to C.

Well, http://doi.acm.org/10.1145/361227.361230
("Exception handling: issues and a proposed notation", Year of Publication: 1975)

PL/I and other historical stuff aside, AFAIK, Digital folks (for example)
had >>C<< exceptions long before they were added to C++ ("part of the C++
reference manual that in 1990 was voted the base document for the C++
standards effort").

ftp://gatekeeper.research.compaq.com/pub/DEC/SRC/research-reports/SRC-040.pdf
("Implementing Exceptions in C", Eric S. Roberts, March 21, 1989)

> The cost of committee membership depends upon your national committee;
> the US committee cost $800/yr. last time I checked, and is open to
> membership by people who aren't from the US.

Well, Y'know, ;-) life is MUCH ``cheaper'' here:

http://www.iso.org/iso/en/aboutiso/isomembers/MemberDetailPage.MemberDetail?MEMBER=BELST

regards,
alexander.

James Russell Kuyper Jr.

unread,
Sep 2, 2002, 4:56:55 PM9/2/02
to
Alexander Terekhov wrote:
...

> But I WANT/NEED to use either C or C++ (more than its C subset)...
> depending on the "situation". ...

Since you need more than the C subset, you obviously can't use C++
everywhere. However, that doesn't add up to a reason for mixed language
use. The question then becomes, why write anything in C? Why not compile
the code that you're currently writing in C, as C++ code? If linkage to
C libraries or legacy code is an issue, suitable use of 'extern "C"'
should handle the problem.

James Russell Kuyper Jr.

unread,
Sep 2, 2002, 5:43:32 PM9/2/02
to
[Please ignore previous version: a small typo made it nonsense]
Alexander Terekhov wrote:
...

> But I WANT/NEED to use either C or C++ (more than its C subset)...
> depending on the "situation". ...

Since you need more than the C subset, you obviously can't use C

Alexander Terekhov

unread,
Sep 3, 2002, 5:13:27 AM9/3/02
to

"James Russell Kuyper Jr." wrote:
>

So, correct me if I'm wrong, but you're basically saying that I
should pretend that ISO C doesn't exist, forget about

http://david.tribble.com/text/cdiffs.htm
(Incompatibilities Between ISO C and ISO C++)

and simply stick to the C subset of ISO C++. Well, "okay". Now,
what if I really want to catch {and finalize} POSIX thread cancel
"exception" raised by something like fclose(), to begin with? ;-)

regards,
alexander.

James Russell Kuyper Jr.

unread,
Sep 3, 2002, 6:06:43 AM9/3/02
to
Alexander Terekhov wrote:
>
> "James Russell Kuyper Jr." wrote:
> >
> > [Please ignore previous version: a small typo made it nonsense]
> > Alexander Terekhov wrote:
> > ...
> > > But I WANT/NEED to use either C or C++ (more than its C subset)...
> > > depending on the "situation". ...
> >
> > Since you need more than the C subset, you obviously can't use C
> > everywhere. However, that doesn't add up to a reason for mixed language
> > use. The question then becomes, why write anything in C? Why not compile
> > the code that you're currently writing in C, as C++ code? If linkage to
> > C libraries or legacy code is an issue, suitable use of 'extern "C"'
> > should handle the problem.
>
> So, correct me if I'm wrong, but you're basically saying that I
> should pretend that ISO C doesn't exist, forget about
>
> http://david.tribble.com/text/cdiffs.htm
> (Incompatibilities Between ISO C and ISO C++)

No, of course you shouldn't ignore those imcompatibilities, if you need
to do mixed language programming. If you have to interface with legacy
or library code written in C, with code of your own that needs to use
C++ features, you can't avoid having to deal with them. However, if you
do need the C++ features, then you're best off dealing with those
incompatibilities by writing most of your own code to be compiled using
C++. Any of your code that calls the C code can use 'extern "C"'
declarations. If the legacy or library code calls functions that you
need to provide, you can define those functions as 'extern "C"', while
compiling them with C++ - keep in mind that the function body for an
'extern "C"' function can use as many C++ features as you want, as long
as they're compatible with the interface - 'extern "C"' only affects the
interface.

> and simply stick to the C subset of ISO C++. Well, "okay". Now,

There's no real need to stick to the C subset. The only point in even
mentioning the subset is to simply point out that, that since it exists,
there's little reason to use C if you also need C++ features. Almost
every feature of C90 is a feature of that subset - most of the ones that
aren't, are features you shouldn't be using anyway, like unprototyped
functions and implicit int. Of course, if you stick to the subset, and
pay careful attention to the incompatibility issues, you can write code
that will compile with either language, with exactly the same meaning,
just by putting the 'extern "C"' declarations inside suitable #ifdef's.
However, I was arguing for a strictly C++ approach to mixed-language
coding, so sticking to the C subset isn't an important issue from my
point of view.

> what if I really want to catch {and finalize} POSIX thread cancel
> "exception" raised by something like fclose(), to begin with? ;-)

Well, that's a POSIX feature; not possessing a copy of that standard, I
can't comment on that issue. However, if POSIX specifies that it's to be
a C++ exception, than you can catch it in C++ code that calls fclose(),
directly or indirectly; any other kind of exception is entirely outside
the range of either the C or C++ standards.

Alexander Terekhov

unread,
Sep 4, 2002, 6:59:43 AM9/4/02
to

"James Russell Kuyper Jr." wrote:
[...]

> > and simply stick to the C subset of ISO C++. Well, "okay". Now,
>
> There's no real need to stick to the C subset. The only point in even
> mentioning the subset is to simply point out that, that since it exists,
> there's little reason to use C if you also need C++ features. Almost
> every feature of C90 is a feature of that subset - most of the ones that
> aren't, are features you shouldn't be using anyway, like unprototyped
> functions and implicit int.

What about all those fancy C99 "extras"?

[...]


> > what if I really want to catch {and finalize} POSIX thread cancel
> > "exception" raised by something like fclose(), to begin with? ;-)
>
> Well, that's a POSIX feature; not possessing a copy of that standard, I
> can't comment on that issue.

Here's free copy of the standard:

http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html#tag_02_09_05
(Thread Cancelation, XSH-Normative volume)

http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_09_20
(Thread Cancelation, Rationale volume)

"The alternative to providing these simple cancelation cleanup
handlers (whose only use is for cleaning up when a thread is
canceled) is to define a general exception package that could
be used for handling and cleaning up after hardware traps and
software-detected errors. This was too far removed from the
charter of providing threads to handle asynchrony. However,
it is an explicit goal of IEEE Std 1003.1-2001 to be
compatible with existing exception facilities and languages
having exceptions."

> However, if POSIX specifies that it's to be a C++ exception,

It's neither {portably} C nor C++ exception, unfortunately.

> than you can catch it in C++ code that calls fclose(),
> directly or indirectly; any other kind of exception is entirely outside
> the range of either the C or C++ standards.

Right, and THAT is just one reason (among many many others) why
you folks should really UNITE under hypothetical WG{14+15+21=}50
"umbrella" and produce POSIX.1++ standard with "C++-core" and a
whole bunch of {already existent(*)} C-OS bindings and {currently
nonexistsent} C++-OS bindings OPTIONS (C and/or C++ extensions}.

regards,
alexander.

(*) http://www.opengroup.org/onlinepubs/007904975/help/codes.html

James Russell Kuyper Jr.

unread,
Sep 4, 2002, 8:08:28 AM9/4/02
to
Alexander Terekhov wrote:
>
> "James Russell Kuyper Jr." wrote:
> [...]
> > > and simply stick to the C subset of ISO C++. Well, "okay". Now,
> >
> > There's no real need to stick to the C subset. The only point in even
> > mentioning the subset is to simply point out that, that since it exists,
> > there's little reason to use C if you also need C++ features. Almost
> > every feature of C90 is a feature of that subset - most of the ones that
> > aren't, are features you shouldn't be using anyway, like unprototyped
> > functions and implicit int.
>
> What about all those fancy C99 "extras"?

IMO many of the new features in C99 that aren't incompatible with C++
should be included in the next release of C++. However, I can't think of
any situation where you actually need to use those features. Exception:
<stdint.h> - you'll need it for the typedefs if you need to use a
function with an interface based upon one or more of those typedefs.
However, <stdint.h> is by far the most easily portable parts of C99.

0 new messages