[net.unix-wizards] Bug iwith setjmp/longjmp on Vax

rosen@gypsy.UUCP (06/06/85)

/*

This program was compiled under 4.2BSD on a VAX; it doesn't work the way it
should (I get a 'longjmp botch' message).  If I compile the same exact
program on a Sun running 4.2BSD it works fine.  I know that setjmp() and
longjmp() work on a Vax, but why is this simple program giving me a problem?

I've been told that this program is too simple for setjmp() and longjmp().
This appears to be true, because if I complicate the code just a bit, it
will work. What's going on?

*/


/* setjmp() - longjmp() test program */

#include <setjmp.h>

static jmp_buf env;
int mode;


main(){
	foo();
	longjmp(env, 1);
}

foo(){

  mode = setjmp(env);
  if (mode != 0) magic();
}

magic()
{
	printf("HERE I AM\n");
	exit(0);
}

/* End of code */

/*

Steve Rosen
Siemens Research and Technology Laboratories
Princeton, NJ

USENET: {ihnp4|princeton|adrvax}!siemens!rosen
ARPA:   princeton!siemens!rosen@TOPAZ

*/

henry@utzoo.UUCP (Henry Spencer) (06/07/85)

> This program was compiled under 4.2BSD on a VAX; it doesn't work the way it
> should (I get a 'longjmp botch' message).  If I compile the same exact
> program on a Sun running 4.2BSD it works fine.  I know that setjmp() and
> longjmp() work on a Vax, but why is this simple program giving me a problem?
> ...
> main(){
> 	foo();
> 	longjmp(env, 1);
> }
> 
> foo(){
>   mode = setjmp(env);
>   ...
> }

To quote the 4.2BSD setjmp(3) manual page (as well as all previous setjmp
manual pages):

	[longjmp] returns in such a way that execution continues as
	if the call of setjmp had jsut returned ... to the function
	that invoked setjmp, *which must not itself have returned in
	the interim*.  [emphasis added]

In other words, your code is wrong.  Put the setjmp in main(), or the
longjmp in foo(), and it will be correct.  It is only accidental that
it works on some machines as it is.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

jim@ISM780B.UUCP (06/08/85)

"Forward, into the past!" -- Firesign Theatre

If you longjmp into a routine that has already returned, just where do you
expect to be?  There is such a thing as stack discipline.
The routine that calls setjmp must be an ancestor of (or equal to, which
is broken on some implementations, such as pdp11 SysIII) the routine that
calls longjmp.  foo is not an ancestor of main.

The VAX 4.2BSD version is correct; it backtraces the stack so the register
variables are restored properly.  The Sun version is, technically,
incorrect; it saves the registers and sp in setjmp and simply restores
them in longjmp.  For details of why this is wrong, refer to the archives;
this has been discussed to death.  For details of why a correct implementation
appears too costly (extra overhead on every call), see same.  Also discussed
there was the simple, clever technique used by the Amsterdam Compiler Kit,
namely any routine that calls a routine called "setjmp" doesn't use register
variables; this doesn't work only if you call setjmp indirectly, which is
a rather bizarre and foolish thing to do.

-- Jim Balter, INTERACTIVE Systems (ima!jim)

chris@umcp-cs.UUCP (Chris Torek) (06/08/85)

Your code has a nasty little no-no in it: it longjmp's after the stack
environment in which the setjmp was done has been deallocated.  No
surprise it fails ``at random''.  Watch:

--------#include <setjmp.h>
--------static jmp_buf env;
--------int mode;
--------main() {
active: env=uninit, mode=0, main()
--------	foo();
[expand foo()]
[]------foo() {
active: env=uninit, mode=0, main(), foo()
[]------	mode = setjmp(env);
active: env=foo(), mode=0, main(), foo()
[]------	if (mode != 0) magic();
[]------}
[return to main()]
active: env=foo() [defunct], mode=0, main()
--------	longjmp(env, 1);

Oops.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

gwyn@brl-tgr.ARPA (06/08/85)

> main(){
> 	foo();
> 	longjmp(env, 1);
> }
> 
> foo(){
> 
>   mode = setjmp(env);
>   if (mode != 0) magic();
> }

"If longjmp is called even though env was never primed by a call to
setjmp, or when the last such call was in a function which has since
returned, absolute chaos is guaranteed."
	- System V Interface Definition

You see, foo()'s stack frame has been totally trashed after he
returned (e.g., arguments to longjmp were pushed onto the stack
at addresses that were formerly part of foo()'s stack frame), and
when the longjmp attempts to reactivate it it no longer makes any
sense..  Sometimes it may work by accident, but it WILL be an accident.

stephen@dcl-cs.UUCP (06/09/85)

In article <44700008@gypsy.UUCP> rosen@gypsy.UUCP writes:
>This program was compiled under 4.2BSD on a VAX; it doesn't work the way it
>should (I get a 'longjmp botch' message).  If I compile the same exact
>program on a Sun running 4.2BSD it works fine.  I know that setjmp() and
>longjmp() work on a Vax, but why is this simple program giving me a problem?
>
>/* setjmp() - longjmp() test program */
>#include <setjmp.h>
>static jmp_buf env;
>int mode;
>
>main(){
>	foo();
>	longjmp(env, 1);
>}
>
>foo(){
>
>  mode = setjmp(env);
>  if (mode != 0) magic();
>}
It has always been my understanding that "longjmp()" is used to jump OUT of
routines - not INTO them!
-- 
Name:	Stephen J. Muir			Project:Alvey ECLIPSE Distribution
JANET:	stephen@uk.ac.lancs.comp	DARPA:	stephen%lancs.comp@ucl-cs
UUCP:	...!ukc!icdoc!dcl-cs!stephen	Phone:	+44 524 65201 Ext. 4599
Post:	Department of Computing, University of Lancaster, Bailrigg, Lancaster.
	LA1 4YR

faustus@ucbcad.UUCP (Wayne A. Christopher) (06/09/85)

> main(){
> 	foo();
> 	longjmp(env, 1);
> }
> 
> foo(){
> 
>   mode = setjmp(env);
>   if (mode != 0) magic();
> }

I think the problem is that you can only longjmp back to somewhere below
where you are on the stack. It resets things like the stack and argument
pointers, and if you have already returned from the routine where you
did the setjmp, you will have problems... I don't know exactly how this
would work, but this is certainly not an intended use of longjmp...

	Wayne