[comp.lang.c++] Bug in C++ cfont with possible fix

wescott@sauron.UUCP (Mike Wescott) (11/16/86)

Paraphrase of a recent comment in net.lang.c:
	"Everyone knows that the first test of a compiler
		is to compile itself."

Well in porting C++ (1.1 and 1.0) to the NCR Tower (MC680x0) machines, C++ 
wouldn't compile itself.  It got a bus error when cfront was working on main.c.
The bug is masked in most architectures by the way alignments of the 'basetype'
and 'fct' derived classes line up.  The bug occurs in print.c when a
reference is assumed to be to the 'fct' class but in fact is to the 'basetype'
class.  On machines with VAX alignments and sizes, a NULL pointer is fetched,
recognized and processing continues.  On my machine, the top half of another
pointer is fetched, and used to try to access low memory.

While masked on the VAX, the bug can be demonstrated by the following function

typedef int (* S)(float);
extern S s;
void x()
{
	(*s)(4);
	s(4);
}

from which cfront produces (stripped of line numbers and comments)

int *_new ();
int _delete ();
int *_vec_new ();
int _vec_delete ();

typedef int (*S )();
extern S s ;
int x ()
{ 
(*s )( (float )4 ) ;
s ( 4 ) ;
}
;

Note first, that both methods of invoking the function *s are legitimate C and
C++.  Note as well, that the second invocation does not get its argument
preceeded by the (float) cast.  This is the bug.  Since both C++ statements are
equivalent, both should produce that same construct for the argument list.

As mentioned above, the problem is in print.c.  As the second statement is
printed, the assumtion is made that since the statement is a "CALL" then "s"
is a function name.  Under that assumtion, print.c tries to determine the type
of the arguments to "s" using the wrong structure.  On the VAX it gives up
because it gets a NULL, on other machines it can go off into never-never land.

A patch follows.  Perhaps Dr. Stroustup will bless or (better yet) improve upon
this.

	-Mike Wescott
	ncrcae!wescott

*** print.c.orig	Sat Nov 15 21:06:04 1986
--- print.c	Sun Nov 16 03:03:31 1986
***************
*** 1372,1377
  		else {
  //error('d',"e1%k e1->tp %d %d%t",e1->base,e1->tp,e1->tp->base,e1->tp);
  			eprint(e1);
  			if (e1->tp)		// pointer to fct 
  				at = Pfct(e1->tp)->argtype;
  			else			// virtual: argtype encoded

--- 1372,1378 -----
  		else {
  //error('d',"e1%k e1->tp %d %d%t",e1->base,e1->tp,e1->tp->base,e1->tp);
  			eprint(e1);
+ #ifdef BUG
  			if (e1->tp)		// pointer to fct 
  				at = Pfct(e1->tp)->argtype;
  			else			// virtual: argtype encoded
***************
*** 1376,1381
  				at = Pfct(e1->tp)->argtype;
  			else			// virtual: argtype encoded
  				at = (Pname)e1->e1->tp;
  		}
  		puttok(LP);
  		if (e2) {

--- 1377,1412 -----
  				at = Pfct(e1->tp)->argtype;
  			else			// virtual: argtype encoded
  				at = (Pname)e1->e1->tp;
+ #else
+ 			if (!(e1->tp))		// virtual: argtype encoded
+ 				at = (Pname)e1->e1->tp;
+ 			else			// look for pointer to fct
+ 				for (at = (Pname)(e1->tp); at ; ) {
+ 					switch (at->base) {
+ 					case FCT:
+ 						at = Pfct(at)->argtype;
+ 						break;
+ 					case ZTYPE:		// is this possible ??
+ 					case ANY:		// is this possible ??
+ 					case TYPE:		// this is !!
+ 						at = Pbase(at)->b_name;
+ 						continue;
+ 					case RPTR:		// is this possible??
+ 					case PTR:		// this is !!
+ 						at = (Pname)(Pptr(at)->typ);
+ 						continue;
+ 					case NAME:		// is this possible??
+ 					case TNAME:		// this is  !!
+ 						at = (Pname)(at->tp);
+ 						continue;
+ 					default:		// what else ??
+ 						error('i',"can't find arglist types");
+ 						at = (Pname) 0;
+ 						break;
+ 					}
+ 					break;
+ 				}
+ #endif
  		}
  		puttok(LP);
  		if (e2) {

karl@haddock.UUCP (11/22/86)

In article <757@sauron.UUCP> wescott@sauron.UUCP (Mike Wescott) writes:
>While masked on the VAX, the bug can be demonstrated by the following:
>typedef int (* S)(float);  extern S s;
>void x() { (*s)(4); s(4); }
>[...]
>Note first, that both methods of invoking the function pointers are
>legitimate C and C++.

They are?  I don't recall seeing this feature described in C++ (but I don't
have any recent documentation).  And it is *not* legitimate oldC -- some
compilers will accept it, but not all.  (It has, alas, been blessed by ANSI,
but the C++ compiler isn't supposed to generate ANSI C output, so the C++
compiler is broken if it silently generates "s((float)4);".  Right?)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

wescott@sauron.UUCP (Mike Wescott) (11/25/86)

In article <175@haddock.UUCP> karl@haddock.UUCP (Karl Heuer) writes:
> In article <757@sauron.UUCP> wescott@sauron.UUCP (Mike Wescott) writes:
> >While masked on the VAX, the bug can be demonstrated by the following:
> >typedef int (* S)(float);  extern S s;
> >void x() { (*s)(4); s(4); }
> >[...]
> >Note first, that both methods of invoking the function pointers are
> >legitimate C and C++.
> 
> They are?  I don't recall seeing this feature described in C++ (but I don't
> have any recent documentation).  And it is *not* legitimate oldC -- some
> compilers will accept it, but not all.  (It has, alas, been blessed by ANSI,
> but the C++ compiler isn't supposed to generate ANSI C output, so the C++
> compiler is broken if it silently generates "s((float)4);".  Right?)

Within a day of posting this article, I cancelled it.  For a more complete 
description of the probllem and a better fix, see <765@sauron.UUCP> and
<766@sauron.UUCP>.

And yes, it is C++ (see sect r7.1 of The C++ Programming Language, p. 256).

And no it's not in K&R.  As for the exact flavor of C that C++ ought to 
generate, I don't know.

By the way, the fix posted in <766@sauron> produces "(*s)((float)4);"
-- 
	-Mike Wescott
	 ncrcae!wescott