[Bug c/40579] New: gcc -O2 optimization causes infinite loop and wrong output
$ gcc -v Using built-in specs. Target: i686-pc-linux-gnu Configured with: /root/gcc-4.4.0/configure --prefix=/opt/gcc-4.4.0 --enable-languages=c,c++ Thread model: posix gcc version 4.4.0 (GCC) Here is a program to reproduce this problem :- #include #include #define MinWordStr "-2147483648" #define MinWord ((long)0x8000) /* smallest word */ /* Simple function to convert long to a string */ static char * itos(long num) { char *p; static char buff[64]; p = buff + sizeof(buff) - 1; *p = '\0'; if (num >= 0L) do { *--p = num % 10L + '0'; num /= 10L; } while (num != 0L); else { if (num == MinWord) { /* max negative value */ p -= strlen (MinWordStr); strcpy (p, MinWordStr); } else { num = -num; do { *--p = '0' + (num % 10L); num /= 10L; } while (num != 0L); *--p = '-'; } } return p; } int main() { char *p; long x = -2147483645; int i; for (i = 0; i < 4; ++i) { p = itos(x); printf("i=%d p=%s\n",i,p); --x; } return 0; } When run with -O1 it runs okay. $ gcc -O1 prog.c && ./a.out i=0 p=-2147483645 i=1 p=-2147483646 i=2 p=-2147483647 i=3 p=-2147483648 But with -O2 it goes haywire. $ gcc -O2 progg.c && ./a.out i=0 p=-2147483645 i=1 p=-2147483646 i=2 p=-2147483647 i=3 p=-2147483648 i=4 p=-./,),(-*,) i=5 p=-./,),(-*,* i=6 p=-./,),(-*,+ i=7 p=-./,),(-*,, ...etc ad infinitum Note that if the line if (num == MinWord) { /* max negative value */ is changed to if (num == -num) { /* max negative value */ a different (and also incorrect) result occurs with -O2 $ gcc -O2 prog.c && ./a.out i=0 p=-2147483645 i=1 p=-2147483646 i=2 p=-2147483647 i=3 p=-./,),(-*,( Other points: 1) this has something to do with the value of x reaching the most negative 32-bit long (ie: -2147483648, or 0x8000) - if it stays away from that by initializing x = -2147483644 instead of -2147483645 it is okay. 2) gcc 2.95.3 seems to work okay with -O2 -- Summary: gcc -O2 optimization causes infinite loop and wrong output Product: gcc Version: 4.4.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: dentongosnell at yahoo dot com GCC build triplet: i686-pc-linux GCC host triplet: i686-pc-linux GCC target triplet: i686-pc-linux http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40579
[Bug c/40645] New: Bus error caused by ldd/std instructions in struct copy.
$ gcc -v Using built-in specs. Target: sparc-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.2-1.1' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --with-cpu=v8 --with-long-double-128 --enable-checking=release --build=sparc-linux-gnu --host=sparc-linux-gnu --target=sparc-linux-gnu Thread model: posix gcc version 4.3.2 (Debian 4.3.2-1.1) To trigger the bug :- $ gcc align_bug.c $ ./a.out Bus error $ Here is align_bug.c :- - #include struct b_one { int i; double d; }; struct b_two { int i1; int i2; }; union myblock { struct b_one one; struct b_two two; }; void myfunc(union myblock *dp1, union myblock *dp2) { dp2->two = dp1->two; } int main() { int w; struct b_two a = {1,2}; struct b_two b; myfunc((union myblock *)&a, (union myblock *)&b); printf("%d %d\n", b.i1, b.i2); return 0; } -- The problem seems to happen in "myfunc" when the compiled code tries to copy the 8-byte structure dp2->two to dp1->two, using a ldd/std instruction pair. The problem seems to be that dp1 and dp2 (ie a and b in main) aren't strictly enough aligned for that. If you take out the redundant "int w" in main then a and b happen to be aligned okay and the bus error doesn't happen. I think the compiler is assuming "union myblock" has the same alignment as "struct b_one", which is more strictly aligned than "struct b_two" because of its double member. I realise that casting &a to (union myblock*) in main may technically invoke undefined behaviour... but I think the cast is reasonable given that union myblock contains the type of a. One other thing, there is a flag "-mno-faster-structs" which this page suggests would prevent this sort of ldd/std use (http://gcc.gnu.org/onlinedocs/gcc/SPARC-Options.html). Unfortunately this flag doesn't seem to make any difference to this case. -- Summary: Bus error caused by ldd/std instructions in struct copy. Product: gcc Version: 4.3.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: dentongosnell at yahoo dot com GCC build triplet: sparc-linux-gnu GCC host triplet: sparc-linux-gnu GCC target triplet: sparc-linux-gnu http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40645
[Bug c/40645] Bus error caused by ldd/std instructions in struct copy.
--- Comment #3 from dentongosnell at yahoo dot com 2009-07-04 13:32 --- (In reply to comment #2) > > > One other thing, there is a flag "-mno-faster-structs" which this page > > suggests would prevent this sort of ldd/std use > > (http://gcc.gnu.org/onlinedocs/gcc/SPARC-Options.html). Unfortunately > > this flag doesn't seem to make any difference to this case. > > -mno-faster-structs is the default. > If "-mno-faster-structs" is the default, then surely it shouldn't be generating ldd/std in this case (and assuming the 8-byte alignment for "union myblock"). The code it is generating is what I would expect if I passed "-mfaster-structs", based on the above-mentioned documentation page. In other words, gcc align_bug.c should give just ld/st pairs, and hence should work without a bus error. I think either the compiler or the documentation has a bug! -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40645