[comp.lang.c++] RETBUG in cfront. Passing/Returning Class Instances.

mikem@otc.OZ (Michael Mowbray) (12/19/86)

(I don't know whether this subject has already been posted, but a reminder
 won't hurt anyway.)

In C++, if a class has a constructor taking a reference to itself, this
is used to advantage whenever instances of that class are passed to or
returned from functions. Essentially, an auxiliary pointer argument is passed
telling the function where the instance is, or where to compose the result,
respectively. This saves a bit-wise copy.

Unfortunately, I understand that a number of c-compilers have a bug that
causes a core dump if nothing is actually returned (when a struct was supposed
to be returned). The C++ translator handles that case by inserting dummy
code when necessary, depending on whether RETBUG was defined when cfront
was compiled. In the default distribution this is the case. So you may be
running a cfront that generates this dummy code (and hence introduces
run-time inefficiencies) even though you don't have to.

The following c program allows you to determine whether your c compiler
has the bug. Compile and run it. If it dumps core you have the bug. If
it doesn't, then you may wish to edit the cfront makefile to undefine
RETBUG, and then re-make cfront.

    struct Crap {
	    int i;
    };

    struct Crap f(cp,ip)
    struct Crap *cp;
    int *ip;
    {
	cp->i = (*ip)++;
	return;
    }

    main()
    {
	struct Crap c;
	int i=0;
	f(&c,&i);

	printf("%d %d\n",c.i,i);	/* should just print:  0 1  */
    }

The Pyramid c compiler is fine. The Sun c compiler is NOT. (I wonder if this
is fixed in the SunOS release.)

I don't recall seeing anything about this in the C++ release notes. Maybe
there ought to be something.... (?)

			Mike Mowbray
			Systems Development
			Overseas Telecommunications Commission (Australia)

UUCP:   {seismo,mcvax}!otc.oz!mikem              ACSnet: mikem@otc.oz

solomon@crys.WISC.EDU (Marvin Solomon) (12/21/86)

Mike Mowbray pointed out that cfront contains an option (turned on in
the default version) to generate code to get around a C compiler bug,
and supplies a test program to check whether your C compiler has that bug.
His instructions are:

> The following c program allows you to determine whether your c compiler
> has the bug. Compile and run it. If it dumps core you have the bug. If
> it doesn't, then you may wish to edit the cfront makefile to undefine
> RETBUG, and then re-make cfront.

Unfortunately, the bug may be present even if the program compiles and
runs "correctly".  The Berkeley 4.3 UNIX compiler for the VAX (as well
as the 4.3beta and, I suspect, all earlier compliers) generates incorrect
code, but the incorrect code is harmless.  It copies a longword from
location 0 to another location.  On a SUN, virtual address 0 is not
a legal address, but on a VAX (under Berkeley UNIX) it is.  To make the
program core dump, change the initialization of i from 0 to -1.  Here
is the modified test program:
	struct Crap {
		int i;
	};

	struct Crap f(cp,ip)
	struct Crap *cp;
	int *ip;
	{
	cp->i = (*ip)++;
	return;
	}

	main()
	{
	struct Crap c;
	int i = -1;
	f(&c,&i);

	printf("%d %d\n",c.i,i);	/* should just print:  0 1  */
	}
And here is the assembler language generated by 'cc -S' (with annotation):
LL0:
	.data
	.text
	.align	1
	.globl	_f
_f:
	.word	L12
	jbr 	L14
L15:
	movl	*8(ap),r0	/ r0 = *ip
	incl	*8(ap)		/ ip++
	movl	r0,*4(ap)	/ cp->i = *ip
	jbr 	L13
L13:
	.lcomm	L16,4		/ return:
	movab	L16,r1		/ r1 = &temp
	movl	(r0),(r1)	/ *r1 = *r0      (!)
	movab	L16,r0		/ return &temp
	ret
	.set	L12,0x0
L14:
	jbr 	L15
	.data
	.text
	.align	1
	.globl	_main
_main:
	.word	L18
	jbr 	L20
L21:
	mnegl	$1,-8(fp)
	subl3	$8,fp,r0
	pushl	r0
	subl3	$4,fp,r0
	pushl	r0
	calls	$2,_f
	.data	1
L23:
	.ascii	"%d %d\12\0"
	.text
	pushl	-8(fp)
	pushl	-4(fp)
	pushl	$L23
	calls	$3,_printf
	ret
	.set	L18,0x0
L20:
	subl2	$8,sp
	jbr 	L21
	.data
-- 
	Marvin Solomon
	Computer Sciences Department
	University of Wisconsin, Madison WI
	solomon@gjetost.wisc.edu or seismo!uwvax!solomon

chris@mimsy.UUCP (Chris Torek) (12/22/86)

In article <213@crys.WISC.EDU> solomon@crys.WISC.EDU (Marvin Solomon) writes:
>... cfront contains an option (turned on in the default version)
>to generate code to get around a C compiler bug. ...

>Unfortunately, the bug may be present even if [a previously posted
>test] program compiles and runs "correctly".  The Berkeley 4.3 UNIX
>compiler for the VAX (as well as the 4.3beta and, I suspect, all
>earlier compliers) generates incorrect code, but the incorrect
>code is harmless.

Sometimes!  It depends on whatever happens to be in r0.  E.g.,

	struct foo { int f; };
	struct foo f() { g(); return; }
	int g() { return (0xc0000000); }
	main() { f(); exit(0); }

will crash.

>Here is the modified test program:
>	struct Crap { int i; };
>	struct Crap f(cp,ip)
>	struct Crap *cp;
>	int *ip;
>	{
>	cp->i = (*ip)++;
>	return;
>	}

This program does indeed point out a bug in the 4.3BSD compiler
(and in lint, which does not complain), but the code itself is
wrong as well.  The function is declared to return an object of
type `struct Crap'; all the paths out of this function must return
such an object.  For example,

	return (*cp);

would be correct.  `return;' is not, nor is falling off the end
of the function without a `return'.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu