[comp.std.c] why does setjmp return 1 after longjmp

libes@cme.nist.gov (Don Libes) (09/16/90)

After being bitten by this, I thought about it awhile and I still find
it odd.  "Portability and the C Language" [Jaeschke] says this is:

	"so that a call to setjmp directly (which returns 0) cannot
	be confused with longjmp's returning through setjmp with a
	value of 0."

I think it's more confusing this way.

If a programmer doesn't want to be confused with setjmp's original
call, then isn't the obvious solution to choose a different value than
0?  Why would someone explicitly say longjmp(buf,0) rather than
longjmp(buf,1)?  It surely can't be for readability!

Has any of you personally ever intentionally written longjmp(buf,0)
knowing that it would return 1?  Or did this become Standard because
of "existing practice" and the thought that it would break working
programs?  (I suspect it would probably fix more programs.)

Was there any discussion about "fixing" this?  I have some old UNIX
manuals that document setjmp returning whatever longjmp says, no
questions asked.  When did this "feature" creep in?

Don Libes          libes@cme.nist.gov      ...!uunet!cme-durer!libes

Oh, and as long as I'm getting my burning questions answered, what
does PJ stand for?

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/16/90)

In article <6511@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:
>Was there any discussion about "fixing" this?

I don't recall any, because it not only reflected existing practice,
it also is obviously essential to prevent a longjmp from returning to
the wrong branch of the setjmp return path.

Every version of longjmp I can recall ever maintaining worked exactly
that way.

cowan@marob.masa.com (John Cowan) (09/17/90)

In article <13866@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <6511@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:
>>Was there any discussion about "fixing" this?
>
>I don't recall any, because it not only reflected existing practice,
>it also is obviously essential to prevent a longjmp from returning to
>the wrong branch of the setjmp return path.

I was bitten by this misfeature once, and had to code around it.

The context was that of a complex operation which could succeed, fail, or
find resource exhaustion.  In the last case, the right thing to do was to
retry the entire operation, by which time the exhaustion would have cleared.

I attempted to implement SUCCESS as "return", FAILURE as "longjmp(buff,1)"
and RETRY as "longjmp(buff,0)".  I reasoned that the last case would cause
a return to the "setjmp" point before the operation began but with a value
of zero, which would cause the operation to begin as if this were the first
time.  Unfortunately, the operation never got retried!

I finally found the relevant line in longjmp(3).  Cursing, I recoded
RETRY as "longjmp(buff,2)" and changed the setjmp conditional from
"if(setjmp(buff)) { main code } else { failure code}" to
"if(setjmp(buff) != 1)".

I know that the ANS put some restrictions on where you can put setjmp()
calls.  Is the above legal ANSI C?  In other words, can you compare the
results of setjmp for non-equality with a constant value?
-- 
cowan@marob.masa.com			(aka ...!hombre!marob!cowan)
			e'osai ko sarji la lojban

guy@auspex.auspex.com (Guy Harris) (09/18/90)

>I don't recall any, because it not only reflected existing practice,
>it also is obviously essential to prevent a longjmp from returning to
>the wrong branch of the setjmp return path.

Even if the person calling "longjmp" screws up and passes a zero
argument?  It would seem that the prevent this from happening by the
simple expedient of not screwing up....

>Every version of longjmp I can recall ever maintaining worked exactly
>that way.

The BSD one doesn't do that; however, a quick check of the V7 version
and the 32V version (from Berkeley's archives, no less) reveals that
they seem to have worked the same way as the S5 one, namely that passing
a return value of 0 is equivalent to passing a return value of 1.

So it looks as if Berkeley are the ones who went off the path, here. 
Fortunately, the ANSI C spec forbids that sort of thing, so 4.4BSD (and
systems that picked up this divergence and haven't yet removed it) will
probably get with the program....

libes@cme.nist.gov (Don Libes) (09/18/90)

I asked why setjmp returns 1 after longjmp(buf,0).

I got some imaginative answers, only one (below) which struck me as
having half a chance of being right.  I also did a little research.
Yes, I really have all these manuals in front of me as I type this.)

V6 didn't have setjmp.  It had setexit/reset, neither of which took
  arguments, and which used a single static buffer.  ugh.

V7 and 4.0BSD setjmp returned 0 after longjmp(buf,0) (according to the manual).
  Guy Harris reports that the V7 source shows it returned 1 after
  longjmp(buf,0).  Either my manuals predate his sources, or Berkeley
  coded from documentation that was incorrect.  (Probably both true!)

S3 (S4, S5) setjmp returned 1 after longjmp(buf,0).

ANSI C setjmp returns 1 after longjmp(buf,0).


Some people agreed with me that the Standard behavior is stooopid,
while admittedly being existing practice.  No one disagreed or claimed
this is a useful feature.  A few people told me they had also been
bitten by this.

The responses I suspect are correct are a paraphrase of the
self-described "wild guesses" of Karl Heuer <karl@kelp.ima.isc.com>
and Scott David Daniels <daniels@cse.ogi.edu>:

Often the only information wanted in a setjmp call is whether it is
from the initialization or a longjmp.  If it had been possible, what
would have been defined was "longjmp with one arg causes a non-zero
return from the corresponding setjmp; with two args it causes the
setjmp to return the second arg." However, as long as longjmp was not
treated specially, such semantics were not possible.

After the "improvement", programmers didn't have to "bother" with
coding the 2nd argument at the price of not being able to return 0.
You may find this hard to swallow, but then you probably never passed
uncasted 0's either.  I think both of these are the mark of
thoughtless programming.

The end result is that the Standard accepted this behavior without
realizing that it was created for a lousy reason.  (Yes, I should've
complained sooner.)

I still claim that no one in their right mind has or ever will write
longjmp(buf,0) knowing that it will return 1.  What's even more
ironic, is that the entire reason for defining it this way (if this
theory is correct), is that being able to write "longjmp(buf)" is now
illegal!

By the way, no one answered my second question either.  Although Karl
Heuer evidentally knows, he wouldn't tell.

>>Oh, and as long as I'm getting my burning questions answered, what
>>does PJ stand for?

>If you knew, you'd respect his decision to always use his initials.  :-)

Don Libes          libes@cme.nist.gov      ...!uunet!cme-durer!libes

rns@se-sd.SanDiego.NCR.COM (Rick Schubert) (09/18/90)

In <6511@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:

>Oh, and as long as I'm getting my burning questions answered, what
>does PJ stand for?

Bill.

-- Rick Schubert (rns@se-sd.sandiego.NCR.COM)

karl@haddock.ima.isc.com (Karl Heuer) (09/19/90)

In article <4075@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
>So it looks as if Berkeley are the ones who went off the path, here.
>Fortunately, the ANSI C spec forbids that sort of thing, so 4.4BSD

This is fortunate?  Surely a better solution would have been for ANSI to make
longjmp(buf,0) undefined behavior instead of guaranteeing the 0->1 kludge.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

guy@auspex.auspex.com (Guy Harris) (09/20/90)

>>Fortunately, the ANSI C spec forbids that sort of thing, so 4.4BSD
>
>This is fortunate?

It's fortunate that ANSI C is saying *something* about the subject, so
that vendors know what they must do and implementors know what they can
count on.

I don't particular care *what* they say; just about anything will work
without too much pain, I don't ever pass "longjmp" a second argument of
0 anyway, and if something that's not ideal in the technical sense is
necessary to get consensus, I can live with it.