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