[4bsd-f77 #33] ASSIGNs to formal parameters don't work in f77
4.2 BSD f77 bug reports
4bsd-f77 at utah-cs.UUCP
Sun Aug 26 17:44:35 AEST 1984
From: Donn Seeley <donn at utah-cs.arpa>
Subject: ASSIGNs to formal parameters don't work in f77
Index: usr.bin/f77 4.2BSD
Description:
If you ASSIGN a line number to a variable that is a formal
parameter of a subroutine, your program will dump core when it
executes a GOTO through that variable. This bug was found by
Jerry Berkman and has been fixed by Bob Corbett and Jerry at
various times; this fix draws on their work and some of my own.
Repeat-By:
Compile the following program (courtesy of Jerry Berkman).
----------------------------------------------------------------
call assok
call assbad(n)
end
subroutine assok
print *, ' in assok '
assign 200 to n
go to n
100 print *, ' should never get here '
200 return
end
subroutine assbad (n)
assign 200 to n
go to n
100 print *, ' should never get here '
200 return
end
----------------------------------------------------------------
When this program is run, it will print something like this:
----------------------------------------------------------------
in assok
in assbad
*** Segmentation violation
Illegal instruction (core dumped)
----------------------------------------------------------------
Fix:
There is a simple way to fix this, but I'm going to present a
more complicated fix that does the job more elegantly. (Famous
last words.)
The immediate problem is that the routine putbranch() in
putpcc.c has some incorrect special case VAX code to handle
GOTOs through formal parameters to subroutines; the latter are
identified by storage class STGARG. Here is the distributed
version of putbranch():
----------------------------------------------------------------
putbranch(p)
register Addrp p;
{
#if TARGET == VAX
if (p->vstg == STGARG)
{
putx(p);
p2op(P2FORCE, P2LONG);
putstmt();
p2pass("\tjmp\t*r0");
return;
}
#endif
putex1(p);
p2op(P2GOTO, P2INT);
putstmt();
}
----------------------------------------------------------------
What this does is compute the operand and convert it to LONG;
since a GOTO has no other expressions, it is guaranteed that
the result of this will end up in register 0, and so
putbranch() emits a VAX instruction intended to cause a
indirect jump through register 0 (carefully wrapped in an
intermediate code instruction which forces the VAX instruction
to appear in the output literally). Unfortunately the
addressing mode '*r0' is illegal and is not reported by the
assembler, which instead generates a ridiculous operand; when
this operand is evaluated the program crashes. The operand the
coder probably wanted was '(r0)', which is reasonable and
allows the program to work.
It occurred to me to wonder why there is a special case for
formal parameters at all, and of course what is going on here
is that the first pass is covering up a bug in the code
generator. The problem is that when presented an operand of
GOTO of the form '*4(ap)' (a typical form for dereferencing a
formal parameter, since arguments to subroutines in f77 are
passed by reference), the code generator produces the
instruction 'jmp **4(ap)', which is just as bogus as 'jmp
*r0'. The assembler DOES detect this error, although its
response is to dump core... You can see all this if you modify
putbranch() in f77pass1/putpcc.c to remove the special case:
----------------------------------------------------------------
*** /tmp/,RCSt1024755 Sun Aug 19 22:31:02 1984
--- putpcc.c Sun Aug 19 20:12:03 1984
***************
*** 199,217
putbranch(p)
register Addrp p;
{
! #if TARGET == VAX
! if (p->vstg == STGARG)
! {
! putx(p);
! p2op(P2FORCE, P2LONG);
! putstmt();
! p2pass("\tjmp\t*r0");
! return;
! }
! #endif
! putex1(p);
p2op(P2GOTO, P2INT);
putstmt();
}
--- 232,240 -----
putbranch(p)
register Addrp p;
{
! putex1((expptr) p);
p2op(P2GOTO, P2INT);
putstmt();
}
----------------------------------------------------------------
Now that I've tricked you into breaking your compiler by making
the preceding change, I'll tell you how to fix it the right
way. It requires a simple one-line change to the code table
(f77/src/f1/table.c) to prevent GOTOs from having indirect
operands:
----------------------------------------------------------------
*** /tmp/,RCSt1024493 Sun Aug 19 20:51:09 1984
--- table.c Sun Aug 19 20:50:52 1984
***************
*** 130,136
" jbr CL\n",
GOTO, FOREFF,
! AWD, TANY,
SANY, TANY,
0, RNOP,
" jmp *AL\n",
--- 144,150 -----
" jbr CL\n",
GOTO, FOREFF,
! SNAME|SOREG, TANY,
SANY, TANY,
0, RNOP,
" jmp *AL\n",
----------------------------------------------------------------
Since no template will now match the GOTO in the example, the
code generator is forced to write the operand out to register;
when this is done the SAREG template matches and everything
works out just the way the original coder wanted it to. GOTOs
through local (SOREG) and COMMON (SNAME) variables use the
changed template safely.
Donn Seeley University of Utah CS Dept donn at utah-cs.arpa
40 46' 6"N 111 50' 34"W (801) 581-5668 decvax!utah-cs!donn
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list