http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51187

             Bug #: 51187
           Summary: gcc 4.6.2 miscompiles genrecog.c when building gcc
                    4.5.3 with --target=avr on Debian/sparc
    Classification: Unclassified
           Product: gcc
           Version: 4.6.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: ju...@wooyd.org


Hello,

We discovered this bug in gcc 4.6.2 in Debian due to build failure of gcc-avr
package on sparc (tracked in Debian as http://bugs.debian.org/648016), which
uses gcc 4.5 source to build an AVR cross-compiler. I was not able to come up
with a nice self-contained test-case, but here are the steps to reproduce the
failure.

1. Download the gcc-4.5.3.tar.bz2 release tarball.
2. Configure it with

./configure -v --enable-languages=c,c++ --prefix=/usr/lib
--infodir=/usr/share/info --mandir=/usr/share/man --bindir=/usr/bin
--libexecdir=/usr/lib --libdir=/usr/lib --enable-shared --with-system-zlib
--enable-long-long --enable-nls --without-included-gettext --disable-checking
--disable-libssp --build=sparc-linux-gnu --host=sparc-linux-gnu --target=avr

Unfortunately, this will probably require binutils-avr to be installed, even
though I believe the build never gets far enough to actually use them.

3. Start the build with 'make' using gcc 4.6. In my case the default Debian
system compiler used to build utilities (including genrecog.c):

jurij@debian:~$ sparc-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=sparc-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/sparc-linux-gnu/4.6/lto-wrapper
Target: sparc-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-4'
--with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.6 --enable-shared --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc
--enable-targets=all --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.6.2 (Debian 4.6.2-4) 

4. Build will fail with the following messages:

[...]
sparc-linux-gnu-gcc -c  -g -O2 -DIN_GCC -DCROSS_DIRECTORY_STRUCTURE  -W -Wall
-Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
-Wmissing-format-attribute -pedantic -Wno-long-long -Wno-variadic-macros
-Wno-overlength-strings -Wold-style-definition -Wc++-compat   -DHAVE_CONFIG_H
-DGENERATOR_FILE -I. -Ibuild -I../.././gcc -I../.././gcc/build
-I../.././gcc/../include -I../.././gcc/../libcpp/include 
-I../.././gcc/../libdecnumber -I../.././gcc/../libdecnumber/dpd
-I../libdecnumber  -DCLOOG_PPL_BACKEND  -I/usr/include/libelf  \
        -o build/genrecog.o ../.././gcc/genrecog.c
sparc-linux-gnu-gcc  -g -O2 -DIN_GCC -DCROSS_DIRECTORY_STRUCTURE  -W -Wall
-Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
-Wmissing-format-attribute -pedantic -Wno-long-long -Wno-variadic-macros
-Wno-overlength-strings -Wold-style-definition -Wc++-compat   -DHAVE_CONFIG_H
-DGENERATOR_FILE  -o build/genrecog \
        build/genrecog.o build/rtl.o build/read-rtl.o build/ggc-none.o
build/vec.o build/min-insn-modes.o build/gensupport.o build/print-rtl.o
build/errors.o ../../build-sparc-linux-gnu/libiberty/libiberty.a
build/genrecog ../.././gcc/config/avr/avr.md \
      insn-conditions.md > tmp-recog.c
/bin/bash: line 1: 22105 Bus error               build/genrecog
../.././gcc/config/avr/avr.md insn-conditions.md > tmp-recog.c
make[2]: *** [s-recog] Error 138
make[2]: Leaving directory
`/home/jurij/gcc/gcc-4.5-upstream/gcc-4.5.3/host-sparc-linux-gnu/gcc'
make[1]: *** [all-gcc] Error 2
make[1]: Leaving directory `/home/jurij/gcc/gcc-4.5-upstream/gcc-4.5.3'
make: *** [all] Error 2

The output of the genrecog.c compilation with -v -save-temps added to the above
command line:

Using built-in specs.
COLLECT_GCC=sparc-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/sparc-linux-gnu/4.6/lto-wrapper
Target: sparc-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-4'
--with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs
--enable-languages=c,c++,fortran,objc,ob
j-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared
--enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=
posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib
--enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plug
in --enable-objc-gc --enable-targets=all --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.6.2 (Debian 4.6.2-4) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-g' '-O2' '-D' 'IN_GCC' '-D'
'CROSS_DIRECTORY_STRUCTURE' '-Wextra' '-Wall' '-Wwrite-strings' '-Wcast-qual'
'-Wstrict-protot
ypes' '-Wmissing-prototypes' '-Wmissing-format-attribute' '-pedantic'
'-Wno-long-long' '-Wno-variadic-macros' '-Wno-overlength-strings'
'-Wold-style-definition' '-Wc++-
compat' '-D' 'HAVE_CONFIG_H' '-D' 'GENERATOR_FILE' '-I' '.' '-I' 'build' '-I'
'../.././gcc' '-I' '../.././gcc/build' '-I' '../.././gcc/../include' '-I'
'../.././gcc/../
libcpp/include' '-I' '../.././gcc/../libdecnumber' '-I'
'../.././gcc/../libdecnumber/dpd' '-I' '../libdecnumber' '-D'
'CLOOG_PPL_BACKEND' '-I' '/usr/include/libelf' '-o
' 'build/genrecog.o' '-mcpu=ultrasparc'
 /usr/lib/gcc/sparc-linux-gnu/4.6/cc1 -E -quiet -v -I . -I build -I ../.././gcc
-I ../.././gcc/build -I ../.././gcc/../include -I ../.././gcc/../libcpp/include
-I ../..
/./gcc/../libdecnumber -I ../.././gcc/../libdecnumber/dpd -I ../libdecnumber -I
/usr/include/libelf -imultilib . -imultiarch sparc-linux-gnu -D__sparc_v9__ -D
IN_GCC -D
 CROSS_DIRECTORY_STRUCTURE -D HAVE_CONFIG_H -D GENERATOR_FILE -D
CLOOG_PPL_BACKEND ../.././gcc/genrecog.c -mcpu=ultrasparc -Wextra -Wall
-Wwrite-strings -Wcast-qual -Ws
trict-prototypes -Wmissing-prototypes -Wmissing-format-attribute -pedantic
-Wno-long-long -Wno-variadic-macros -Wno-overlength-strings
-Wold-style-definition -Wc++-comp
at -g -fworking-directory -O2 -fpch-preprocess -o genrecog.i
ignoring nonexistent directory "/usr/local/include/sparc-linux-gnu"
ignoring nonexistent directory
"/usr/lib/gcc/sparc-linux-gnu/4.6/../../../../sparc-linux-gnu/include"
ignoring nonexistent directory "../.././gcc/build"
#include "..." search starts here:
#include <...> search starts here:
 .
 build
 ../.././gcc
 ../.././gcc/../include
 ../.././gcc/../libcpp/include
 ../.././gcc/../libdecnumber
 ../.././gcc/../libdecnumber/dpd
 ../libdecnumber
 /usr/include/libelf
 /usr/lib/gcc/sparc-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/sparc-linux-gnu/4.6/include-fixed
 /usr/include/sparc-linux-gnu
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-g' '-O2' '-D' 'IN_GCC' '-D'
'CROSS_DIRECTORY_STRUCTURE' '-Wextra' '-Wall' '-Wwrite-strings' '-Wcast-qual'
'-Wstrict-prototypes' '-Wmissing-prototypes' '-Wmissing-format-attribute'
'-pedantic' '-Wno-long-long' '-Wno-variadic-macros' '-Wno-overlength-strings'
'-Wold-style-definition' '-Wc++-compat' '-D' 'HAVE_CONFIG_H' '-D'
'GENERATOR_FILE' '-I' '.' '-I' 'build' '-I' '../.././gcc' '-I'
'../.././gcc/build' '-I' '../.././gcc/../include' '-I'
'../.././gcc/../libcpp/include' '-I' '../.././gcc/../libdecnumber' '-I'
'../.././gcc/../libdecnumber/dpd' '-I' '../libdecnumber' '-D'
'CLOOG_PPL_BACKEND' '-I' '/usr/include/libelf' '-o' 'build/genrecog.o'
'-mcpu=ultrasparc'
 /usr/lib/gcc/sparc-linux-gnu/4.6/cc1 -fpreprocessed genrecog.i -quiet
-dumpbase genrecog.c -mcpu=ultrasparc -auxbase-strip build/genrecog.o -g -O2
-Wextra -Wall -Wwrite-strings -Wcast-qual -Wstrict-prototypes
-Wmissing-prototypes -Wmissing-format-attribute -pedantic -Wno-long-long
-Wno-variadic-macros -Wno-overlength-strings -Wold-style-definition
-Wc++-compat -version -o genrecog.s
GNU C (Debian 4.6.2-4) version 4.6.2 (sparc-linux-gnu)
        compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0,
MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C (Debian 4.6.2-4) version 4.6.2 (sparc-linux-gnu)
        compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0,
MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 9af244203689b6207cc96ca7373030e6
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-g' '-O2' '-D' 'IN_GCC' '-D'
'CROSS_DIRECTORY_STRUCTURE' '-Wextra' '-Wall' '-Wwrite-strings' '-Wcast-qual'
'-Wstrict-prototypes' '-Wmissing-prototypes' '-Wmissing-format-attribute'
'-pedantic' '-Wno-long-long' '-Wno-variadic-macros' '-Wno-overlength-strings'
'-Wold-style-definition' '-Wc++-compat' '-D' 'HAVE_CONFIG_H' '-D'
'GENERATOR_FILE' '-I' '.' '-I' 'build' '-I' '../.././gcc' '-I'
'../.././gcc/build' '-I' '../.././gcc/../include' '-I'
'../.././gcc/../libcpp/include' '-I' '../.././gcc/../libdecnumber' '-I'
'../.././gcc/../libdecnumber/dpd' '-I' '../libdecnumber' '-D'
'CLOOG_PPL_BACKEND' '-I' '/usr/include/libelf' '-o' 'build/genrecog.o'
'-mcpu=ultrasparc'
 as -s -Av9a -32 -relax -o build/genrecog.o genrecog.s
COMPILER_PATH=/usr/lib/gcc/sparc-linux-gnu/4.6/:/usr/lib/gcc/sparc-linux-gnu/4.6/:/usr/lib/gcc/sparc-linux-gnu/:/usr/lib/gcc/sparc-linux-gnu/4.6/:/usr/lib/gcc/sparc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/sparc-linux-gnu/4.6/:/usr/lib/gcc/sparc-linux-gnu/4.6/../../../sparc-linux-gnu/:/usr/lib/gcc/sparc-linux-gnu/4.6/../../../../lib/:/lib/sparc-linux-gnu/:/lib/../lib/:/usr/lib/sparc-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/sparc-linux-gnu/4.6/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-g' '-O2' '-D' 'IN_GCC' '-D'
'CROSS_DIRECTORY_STRUCTURE' '-Wextra' '-Wall' '-Wwrite-strings' '-Wcast-qual'
'-Wstrict-prototypes' '-Wmissing-prototypes' '-Wmissing-format-attribute'
'-pedantic' '-Wno-long-long' '-Wno-variadic-macros' '-Wno-overlength-strings'
'-Wold-style-definition' '-Wc++-compat' '-D' 'HAVE_CONFIG_H' '-D'
'GENERATOR_FILE' '-I' '.' '-I' 'build' '-I' '../.././gcc' '-I'
'../.././gcc/build' '-I' '../.././gcc/../include' '-I'
'../.././gcc/../libcpp/include' '-I' '../.././gcc/../libdecnumber' '-I'
'../.././gcc/../libdecnumber/dpd' '-I' '../libdecnumber' '-D'
'CLOOG_PPL_BACKEND' '-I' '/usr/include/libelf' '-o' 'build/genrecog.o'
'-mcpu=ultrasparc'

I'm attaching genrecog.i produced by that.

My analysis indicates that failure happens due to a miscompilation of
genrecog.c by gcc 4.6.2. Here's the debugging information I posted to the
Debian bug already (note that this was done using gcc-avr Debian source
package, so running genrecog in pristine 4.5.3 produces slightly different
output, but I believe that it still crashes due to same reason):

This bug really is in gcc-4.6, because it is currently the default sid 
gcc and it is used to (mis)compile src/build/genrecog.c during 
gcc-avr build, which later crashes. I'm fairly certain that this is 
gcc problem, because if the binary is compiled with -O0, the problem 
goes away. All debugging output below was obtained on a sparc machine 
running up-to-date sid, invoking build/genrecog under gdb with a 
single argument of '../../src/gcc/config/avr/avr.md'.

Tracing the execution is somewhat tricky, since failure happens within 
write_tree(), and most of the functions write_tree() calls 
(write_tree_1, write_switch, write_node, write_action, etc) are
optimized out. The output generated by 

build/genrecog ../../src/gcc/config/avr/avr.md

is the same as the one produced on an amd64 system until we hit the 
following code in genrecog.c/write_switch(): 

  else if (type == DT_mode
       || type == DT_veclen
       || type == DT_elt_zero_int
       || type == DT_elt_one_int
       || type == DT_elt_zero_wide_safe)
    {
      const char *indent = "";

      /* We cast switch parameter to integer, so we must ensure that the value
     fits.  */
      if (type == DT_elt_zero_wide_safe)
    {
      indent = "  ";
      printf("  if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth);
    }
      printf ("%s  switch (", indent);
      switch (type)
    {
    case DT_mode:
      printf ("GET_MODE (x%d)", depth);
      break;
    case DT_veclen:
      printf ("XVECLEN (x%d, 0)", depth);
      break;
    case DT_elt_zero_int:
      printf ("XINT (x%d, 0)", depth);
      break;
    case DT_elt_one_int:
      printf ("XINT (x%d, 1)", depth);
      break;
    case DT_elt_zero_wide_safe:
      /* Convert result of XWINT to int for portability since some C
         compilers won't do it and some will.  */
      printf ("(int) XWINT (x%d, 0)", depth);
      break;
    default:
      gcc_unreachable ();
    }

The problem appears after executing the 

printf ("%s  switch (", indent);

statetement. It looks like compiler generates a number of small stubs 
within write_tree() for calling printf with all possible format 
statements. Here's how the generated assembler code looks for this 
particular one, starting at 0x00013e60:

Dump of assembler code from 0x13e40 to 0x13ea0:
   0x00013e40 <write_tree+2144>:    ld  [ %i5 + 0x1c ], %o2
   0x00013e44 <write_tree+2148>:    sethi  %hi(0x1e800), %o0
   0x00013e48 <write_tree+2152>:    or  %l1, 0x110, %o1
   0x00013e4c <write_tree+2156>:    call  0x3510c <printf@plt>
   0x00013e50 <write_tree+2160>:    or  %o0, 0x258, %o0
   0x00013e54 <write_tree+2164>:    b  %xcc, 0x13bf4 <write_tree+1556>
   0x00013e58 <write_tree+2168>:    ld  [ %i0 ], %i5
   0x00013e5c <write_tree+2172>:    be,pn   %icc, 0x13850 <write_tree+624>
=> 0x00013e60 <write_tree+2176>:    sethi  %hi(0x1f400), %i3
   0x00013e64 <write_tree+2180>:    sethi  %hi(0x1e800), %o0
   0x00013e68 <write_tree+2184>:    or  %o0, 0x2b0, %o0    ! 0x1eab0
   0x00013e6c <write_tree+2188>:    call  0x3510c <printf@plt>
   0x00013e70 <write_tree+2192>:    or  %i3, 0xe8, %o1
   0x00013e74 <write_tree+2196>:    cmp  %l7, 7
   0x00013e78 <write_tree+2200>:    sll  %l7, 2, %g1
   0x00013e7c <write_tree+2204>:    sethi  %hi(0x1e800), %o0
   0x00013e80 <write_tree+2208>:    mov  %l6, %o1
   0x00013e84 <write_tree+2212>:    call  0x3510c <printf@plt>
   0x00013e88 <write_tree+2216>:    or  %o0, 0x3e8, %o0
   0x00013e8c <write_tree+2220>:    b  %xcc, 0x13bac <write_tree+1484>
   0x00013e90 <write_tree+2224>:    ld  [ %fp + -192 ], %g3
   0x00013e94 <write_tree+2228>:    b  %xcc, 0x13ad0 <write_tree+1264>
   0x00013e98 <write_tree+2232>:    st  %g2, [ %fp + -188 ]
   0x00013e9c <write_tree+2236>:    cmp  %g0, %i3
End of assembler dump.

Confirmation that 0x1eab0 contains the correct format statement 
(passed to printf in %o0):

(gdb) printf "%s\n", (char *) 0x1eab0
%s  switch (
(gdb)

A remarkable feature of this stub is that it does not have a return 
branch statement, like others do (see 0x00013e54, for example). So, 
instead of returning to the correct location where the stub was 
invoked in write_switch(), we fall through to 0x00013e74, and start 
executing the next stub, which invokes printf with a format 
statement at 0x1ebe8 (== 0x1e800 | 0x3e8):

(gdb) printf "%s\n", (char *) 0x1ebe8
%sreturn gen_split_%d (insn, operands);

(gdb) 

This is completely unrelated code, normally invoked by 
write_action(), line 2182. Once it's done, we jump back to completely 
wrong location at 0x00013e8c, eventually causing a crash.

Reply via email to