setjmp/longjmp

david at imd.UUCP david at imd.UUCP
Thu Nov 1 15:28:15 AEST 1984


>***** imd:net.lang.c / brl-tgr!gwyn /  9:56 am  Oct 30, 1984
>I agree with Dennis Ritchie that longjmp should resume after the call
>to setjmp with all accessible data containing values as of the time of
>the longjmp.  This can always be implemented, although some C run-time
>designs seem to have not saved enough information on the call stack to
>support longjmp.  Such implementations need to be changed.  Any system
>where a subroutine call saves all the non-scratch registers (e.g., PDP-11,
>Gould) is in good shape, as is any system where the number of registers
>actually saved is recorded in the call frame (e.g. VAX).  Other systems
>may have to have their calling sequences re-engineered, but that is what
>they deserve for taking shortcuts.

Perhaps setjmp/longjmp can always be  implemented.   However  its
correct   implementation   is  at  the  expense  of  performance.
However, I would disagree that the "pdp-11  is  in  good  shape".
Either  it works 100% of the time, or it should not be relied on.
The following bugs indicate to me that it would be a lot of  work
to get setjmp/longjmp to work ALL THE TIME on the pdp11.  

The following code shows a problem with setjmp/longjmp in that if 
a routine does not follow  proper  register  saving  conventions,
then longjmp cannot know that a register was saved temporarily.  

Our (system 3, I believe) ritchie pdp11 C compiler  (C  rel  2.3;
UTS  rel  1.3)  generates a push and restore of register 2 around
structure copies.  If a longjmp is needed  during  the  structure
copy,   longjmp   will  have  no  idea  that  this  register  was
temporarily used for the structure copy.  

In the following code, the register variables are set to -1,  and
never  used.   Hence  after  a  longjmp,  they  should all be -1.
However, longjmp does not realize that register 2  was  saved  on
the  stack  for the structure copy (as it was not done via csav).
Hence, when the longjmp occurs, register variable 'k' is restored 
to an incorrect value (which I believe is  the  number  of  words
left for the structure copy).   [Note  that  the  following  code
works  correctly  with  a  pdp11 pcc compiler, but fails with the
ritchie compiler, since the code that pcc  is  generating  is  so
silly].  

struct  {
	char    array[16000];
	}       astruct, bstruct;

int     jmpbuf[32];

int     alarmrtn ();

main () {
	register    int     i, j, k;

	for (;;) {
	    i = j = k = -1;             /* set all register vars to -1.     */
	    if (setjmp (jmpbuf) == 0)
		break;
	    printf ("i = %d, j = %d, k = %d\n", i, j, k);
	    }

	signal (14, alarmrtn);          /* cause longjmp after 1 second.    */
	alarm (1);                      /* set alarm higher for a busy      */
	for (;;)                        /* system to be sure gets into loop.*/
	    astruct = bstruct;          /* structure copy of 16000 bytes.   */
	}

alarmrtn ()
{
	longjmp (jmpbuf, 1);
	}


A similar problem occurs in libc.a  or  other  assembly  language
routines  that  do  not  use proper csav subroutine linkage.  For
example  our  Strncmp(3)  in  libc.a  [which  may  not   be   the
distributed strncmp] is written in assembler, and again saves and 
restores register 2.

However, even if one fixes these problems, one has to  fix  csav!
Our  csav  is  setting  up  a  new frame (r5) prior to saving the
registers, hence if  one  longjmps  from  an  intr/alarm  from  2
instructions  inside  csav,  [easiest way is with a debugger] all
register variables get clobbered!

Also, it is possible on the pdp11 to leave the floating point  in
the  wrong  int/long  (seti/setl)  mode after a longjmp.  This is
probably worse than registers getting  clobbered.   This  can  be
caused  by a similar longjmp occuring during an intr/alarm of the
C  code:  long  =  double;  This  bug  can   give   core   dumps!
Unfortunately, the obvious fix requires putting in floating point 
into  programs that have setjmp, even if they do not use floating
point.  [Which may break "ed" on  pdp's  without  floating  point
when one hits <intr>].  

So, even though I use setjmp/longjmp when I have to, didn't  your
mother ever tell you to stay away from setjmps/longjmps?  :-) 


	These views are my own, and are probably wrong!

	    David Marx
	    ima!imd!david



More information about the Comp.lang.c mailing list