This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
an evil memcpy() optimizer bug! (egcs-1.1.2, alphaev6, linux)
- To: egcs-bugs at egcs dot cygnus dot com, egcs at egcs dot cygnus dot com, axp-list at redhat dot com
- Subject: an evil memcpy() optimizer bug! (egcs-1.1.2, alphaev6, linux)
- From: abel at bfr dot co dot il (Alexander L. Belikoff)
- Date: 12 Jul 1999 17:26:45 +0300
Hello everybody,
While porting our code to Alpha dp264 (ev6), I've found the following
bug, that bit us quite painfully. It maybe the case that somebody
reported it before, but then it is unclear why nobody bothered to
issue an emergency bugfix release (1.1.3?). This one really looks like
a major showstopper...
I. The environment:
Alpha dp264 (dual-CPU), running RedHat Linux 5.2 with kernel 2.2.10
(w/ d-ansn-2).
Bothe "native" compiler (egcs 1.0.3) and egcs 1.1.2 installed (the
latter built manually and installed in /usr/local/egcs). The latter
shows:
$ gcc -v
Reading specs from /usr/local/egcs/lib/gcc-lib/alphaev6-unknown-linux-gnu/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
II. Short description of the bug:
When optimized, memcpy() function IN SOME CASES doesn't properly copy
the data.
III. The program (it is as minimal as it could be - the main bulk of
the source is the hexdump function):
============================================================================
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void
hexdump(
FILE* fp, /* in - output stream */
char* name, /* in - dump name (or NULL) */
char* buf, /* in - buffer to dump */
const size_t len /* in - buffer length */
)
{
int i, j;
assert(fp != NULL);
assert(buf != NULL);
assert(len > 0);
#define LMAX 16 /* number of bytes per line */
fprintf(fp, "\n=== %s dump at %p (%d bytes) ====================\n",
(name ? name : ""), buf, (int) len);
for (i = 0; i < len; i += LMAX) {
unsigned short* ibuf = (unsigned short*) &buf[i];
fprintf(fp, "%04d-%04d ", i,
(int) ((i + LMAX - 1 < len) ? i + LMAX - 1 : len));
for (j = 0; j < LMAX / 2; j++) {
if (i + j * 2 >= len) {
fprintf(fp, "%*s", (LMAX / 2 - j) * 5, "");
break;
}
fprintf(fp, "%04X ", ibuf[j]);
}
fprintf(fp, " ");
for (j = 0; j < LMAX; j++) {
char c;
if (i + j >= len)
break;
c = isprint(buf[i + j]) ? buf[i + j] : '.';
fprintf(fp, "%c", c);
}
fprintf(fp, "\n");
}
fprintf(fp, "========================================================="
"==================\n\n");
}
void
put_f8(
double v, /* in - value */
char* buf /* in - destination address */
)
{
v = 99.875;
hexdump(stdout, "pack_f8: v", (char*) &v, 8);
memcpy(buf, &v, 8);
hexdump(stdout, "pack_f8: buf", (char*) buf, 8);
}
int
main()
{
double foovar = 0.05;
double dbuf[3];
memset(dbuf, '\0', sizeof(dbuf));
put_f8(foovar, (char*) &dbuf);
exit(1);
}
/*
Local Variables:
compile-command: "gcc -O2 -g packbug.c -o packbug"
End:
*/
=============================================================================
(the corresponding .i file is attached below)
IV. A bug demo session.
The program tries to write a double prec. value into a buffer, using
memcpy(). The value hexdump is printed before memcpy(), and the buffer
hexdump is printed after it - they don't match in the environment
above, IF the compiler is egcs 1.1.2, AND -O2 is used. There may be
other combinations, however, showing the same bug.
a. a "buggy" session:
$ gcc -v
Reading specs from /usr/local/egcs/lib/gcc-lib/alphaev6-unknown-linux-gnu/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
$ gcc -Wall -O2 -g packbug.c -o packbug
$ ./packbug
=== pack_f8: v dump at 0x11ffff6e0 (8 bytes) ====================
0000-0008 0000 0000 F800 4058 ......X@
===========================================================================
=== pack_f8: buf dump at 0x11ffff700 (8 bytes) ====================
0000-0008 0000 0000 0000 0000 ........
===========================================================================
b. no optimization
$ gcc -v
Reading specs from /usr/local/egcs/lib/gcc-lib/alphaev6-unknown-linux-gnu/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
$ gcc -Wall -g packbug.c -o packbug
$ ./packbug
=== pack_f8: v dump at 0x11ffff6e0 (8 bytes) ====================
0000-0008 0000 0000 F800 4058 ......X@
===========================================================================
=== pack_f8: buf dump at 0x11ffff708 (8 bytes) ====================
0000-0008 0000 0000 F800 4058 ......X@
===========================================================================
c. egcs 1.0.3
$ /usr/bin/gcc -v
Reading specs from /usr/lib/gcc-lib/alpha-redhat-linux/egcs-2.90.29/specs
gcc version egcs-2.90.29 980515 (egcs-1.0.3 release)
$ /usr/bin/gcc -Wall -O2 -g packbug.c -o packbug
$ ./packbug
=== pack_f8: v dump at 0x11ffff6e0 (8 bytes) ====================
0000-0008 0000 0000 F800 4058 ......X@
===========================================================================
=== pack_f8: buf dump at 0x11ffff700 (8 bytes) ====================
0000-0008 0000 0000 F800 4058 ......X@
===========================================================================
Regards,
PS. Here is a cpp'ed file:
packbug.i.gz
--
Alexander L. Belikoff
Bloomberg L.P. / BFM Financial Research Ltd.
abel@vallinor4.com, abel@bfr.co.il