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