eggert@twinsun.com (Paul Eggert) (10/14/89)
GCC's structure-returning convention doesn't work if the structure being returned was copied from a source that overlaps the destination that the returned value will be assigned to. I'm reluctant to report this bug because: Fixing the bug will probably slow down the code GCC generates. The bug is rare in real programs. The proposed ANSI standard is not completely clear. I think the standard should change here to agree with GCC, to avoid needless copying code in structure-returning function calls. However, GCC doesn't behave properly for the program below. Any of the following actions makes the program behave properly: 1. Use -fpcc-struct-return on the Sun-3. (On the Sun-4, the bug persists even with -fpcc-struct-return.) 2. Use Sun's C compiler (either Sun-3 or Sun-4) instead of GCC. 3. Replace ``return *p;'' in the program below with { struct s temp = *p; return temp; } This statement is equivalent to ``return *p;'' because functions yield values, not lvalues, and copying a value does not affect the value. In the program below, the statement ``*p = indirection(q);'' should yield a copy of *q, and assign the copy to *p correctly even though *p and *q overlap. Clearly the statement ``*p = *q;'' would violate the overlap restriction of pANS 3.3.16.1. But because of the implicit copy, ``*p = indirection(q);'' does not violate the overlap restriction. struct s { int i, j, k, l; }; struct s indirection(q) struct s *q; { return *q; } void copycheck(p, q) struct s *p, *q; { q->i = 1; q->j = 2; q->k = 3; q->l = 4; *p = indirection(q); printf( "%d, %d, %d, %d should be 1, 2, 3, 4\n", p->i, p->j, p->k, p->l ); } union { struct { struct s s; int t; } s1; struct { int t; struct s s; } s2; } u; int main() { copycheck(&u.s1.s, &u.s2.s); copycheck(&u.s2.s, &u.s1.s); return 0; } The following transcript shows GCC 1.36 (Sun-3/260, SunOS 4.0.3), improperly behaves as though the overlap restriction is violated. 13-burns% gcc -v u.c gcc version 1.36 /local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68020 u.c /usr/tmp/cca04256.cpp GNU CPP version 1.36 /local/lib/gcc-cc1 /usr/tmp/cca04256.cpp -quiet -dumpbase u.c -version -o /usr/tmp/cca04256.s GNU C version 1.36 (68k, MIT syntax) compiled by GNU C version 1.36. default target switches: -m68020 -mc68020 -mbitfield /local/lib/gcc-as -mc68020 -o u.o /usr/tmp/cca04256.s ld -e start -dc -dp /lib/crt0.o /lib/Fcrt1.o u.o /local/lib/gcc-gnulib -lc 14-burns% ./a.out 1, 2, 3, 4 should be 1, 2, 3, 4 1, 1, 1, 1 should be 1, 2, 3, 4 On a Sparcstation-1 (SunOS 4.0.3c), the output is wrong in a different way, because the structure is copied in reverse order. 40-rise% gcc -v u.c gcc version 1.36 /local/lib/gcc-cpp -v -undef -D__GNUC__ -Dsparc -Dsun -Dunix -D__sparc__ -D__sun__ -D__unix__ u.c /usr/tmp/cca01886.cpp GNU CPP version 1.36 /local/lib/gcc-cc1 /usr/tmp/cca01886.cpp -quiet -dumpbase u.c -version -o /usr/tmp/cca01886.s GNU C version 1.36 (sparc) compiled by GNU C version 1.36. default target switches: -mfpu -mepilogue as -o u.o /usr/tmp/cca01886.s ld -e start -dc -dp /lib/crt0.o u.o /local/lib/gcc-gnulib -lc 41-rise% ./a.out 4, 4, 4, 4 should be 1, 2, 3, 4 1, 2, 3, 4 should be 1, 2, 3, 4