[gnu.gcc.bug] bug in atof_m68k

donn@CS.UTAH.EDU (Donn Seeley) (10/28/89)

[I tried sending this to bug-gas@prep, but evidently the sendmail on
prep lies when it says that the address exists because the mail
bounced...  Sorry to bother GCC fixers with this; maybe the GAS fixers
are reading this too?]

It will be hard to duplicate this yourself, but here's how it happened
to us.  We built GAS 1.34 with GCC 1.36 -O -fstrength-reduce on our
68000-based HP 9000/370 running 4.3 BSD, and it began dumping core when
asked to assemble code that contained certain combinations of floating
point constants.  The following short example, boiled down from the
Berkeley math library cosh() function, was sufficient to elicit the
problem:

	.data
		.even
	_small.2:
		.double 0r1
	.text
		.even
	.globl _cosh
	_cosh:
		link a6,#0
		fcmpd #0r.5,fp2
		rts

Investigation with the debugger revealed that strength reduction had
increased the amount of stack allocated by the function m68_ip() in
m68k.c, and something stomped on a pointer stored on the stack,
causing the assembler to get a segmentation fault the next time the
pointer was dereferenced.  Tracing showed that the trashing occurred
during a call to get_num().  Eventually we isolated the problem --
flonum_multip() was writing into generic_floating_point_number's
buffer, but the buffer address was on the stack!  More specifically,
get_num() wrote over the pointer on the stack with the exponent and
high bits of the mantissa from (appropriately) a NaN.  It was very
surprising to me to find that generic_floating_point_number's buffer
was on the stack, but a grep of the source showed that atof_m68k() sets
generic_floating_point_number.low to a stack buffer.  This would be
fine if all uses of the buffer were under a call to atof_m68k(), but
operand() in expr.c calls atof_generic() without going through
atof_m68k() and as a result when flonum_multip() is called with
&generic_floating_point_number as a target, a random piece of stack is
blown away.

It seems fairly clear that generic_floating_point_number's buffer
should never be on the stack.  The following change to atof-m68k.c
prevents our core dumps:

*** /tmp/,RCSt1000876	Sat Oct 28 01:09:31 1989
--- atof-m68k.c	Sat Oct 28 00:58:40 1989
***************
*** 145,151 ****
       char		what_kind; /* 'd', 'f', 'g', 'h' */
       LITTLENUM_TYPE *	words;	/* Build the binary here. */
  {
! 	LITTLENUM_TYPE	bits [MAX_PRECISION + MAX_PRECISION + GUARD];
  				/* Extra bits for zeroed low-order bits. */
  				/* The 1st MAX_PRECISION are zeroed, */
  				/* the last contain flonum bits. */
--- 145,151 ----
       char		what_kind; /* 'd', 'f', 'g', 'h' */
       LITTLENUM_TYPE *	words;	/* Build the binary here. */
  {
! 	static LITTLENUM_TYPE	bits [2 * MAX_PRECISION + GUARD];
  				/* Extra bits for zeroed low-order bits. */
  				/* The 1st MAX_PRECISION are zeroed, */
  				/* the last contain flonum bits. */

Donn Seeley    University of Utah CS Dept    donn@cs.utah.edu
40 46' 6"N 111 50' 34"W    (801) 581-5668    utah-cs!donn

PS -- A note: the 'generic_buffer' hack in expr.c is NOT guaranteed
to work.  GCC, unlike PCC, does not always lay out data objects in
the order they are declared...  Fortunately, as the above bug shows
:-), the 68k GAS doesn't use the normal buffer.