Created attachment 23585 [details] preprocessed source file The attached preprocessed source file is a much-simplified version of a more complex class hierarchy involving several levels of virtual inheritance and empty classes in the hierarchy. "g++ -v" details: Using built-in specs. Target: i686-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux Thread model: posix gcc version 4.4.5 20101112 (Red Hat 4.4.5-2) (GCC) Also tested with a new build: Using built-in specs. COLLECT_GCC=./g++ Target: i686-pc-linux-gnu Configured with: ./configure Thread model: posix gcc version 4.5.2 (GCC) Among others. Compile with "g++ -c vtable-bug.i". What we observe (tested on x86 and ARM) is that "operator new" is called to allocate 12 bytes for the class (and sizeof matches that 12 byte size), but the compiled code then proceeds to load four-byte 0's into offsets 0, 4, 8, AND 12 from the allocated buffer, stomping data at byte offsets 12-15. (More complex hierarchies can result in more than one 4-byte offset being stomped, and/or the same offset being initialized repeatedly.) Changing which classes are virtual, or adding data to empty base classes, changes or fixes the behavior.
On x86_64 with valgrind: ==31260== Invalid write of size 8 ==31260== at 0x4006E0: BadStuffHere() (t.cc:38) ==31260== by 0x400703: main (t.cc:43) ==31260== Address 0x5936058 is 0 bytes after a block of size 24 alloc'd ==31260== at 0x4C24DFA: operator new(unsigned long) (vg_replace_malloc.c:261) ==31260== by 0x4006C6: BadStuffHere() (t.cc:38) ==31260== by 0x400703: main (t.cc:43)
Confirmed, there was no valgrind errors in 4.3.5.
I think this started with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=138355
I think the problem is that build_zero_init isn't aware of the DECL_FIELD_IS_BASE FIELD_DECLs and CLASSTYPE_AS_BASE stuff. So when simplify_aggr_init_expr decides to call build_zero_init on the SpecificImplementation type, while the first FIELD_DECL has size 8 and its type also size 8, the second FIELD_DECL has size 12 (CLASSTYPE_SIZE_UNIT), its type has size 24 and thus what build_zero_init returns on the subtype isn't directly usable as ctor of the outer type.
Author: jakub Date: Fri Mar 11 15:43:37 2011 New Revision: 170874 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170874 Log: PR c++/48035 * init.c (build_zero_init_1): Extracted from build_zero_init. Add FIELD_SIZE argument, if non-NULL and field bit_position as not smaller than that, don't add that field's initializer. Pass DECL_SIZE as last argument to build_zero_init_1 for DECL_FIELD_IS_BASE fields. (build_zero_init): Use build_zero_init_1. * g++.dg/inherit/virtual8.C: New test. Added: trunk/gcc/testsuite/g++.dg/inherit/virtual8.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/init.c trunk/gcc/testsuite/ChangeLog
Fixed on the trunk so far.
FWIW, I'm confirming both the bug and the fix in a 4.5-based tree.
Author: rguenth Date: Mon Apr 18 14:02:22 2011 New Revision: 172647 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172647 Log: 2011-04-18 Richard Guenther <rguenther@suse.de> Backported from 4.6 branch 2011-03-11 Jakub Jelinek <jakub@redhat.com> PR c++/48035 * init.c (build_zero_init_1): Extracted from build_zero_init. Add FIELD_SIZE argument, if non-NULL and field bit_position as not smaller than that, don't add that field's initializer. Pass DECL_SIZE as last argument to build_zero_init_1 for DECL_FIELD_IS_BASE fields. (build_zero_init): Use build_zero_init_1. * g++.dg/inherit/virtual8.C: New test. 2011-03-05 Zdenek Dvorak <ook@ucw.cz> PR rtl-optimization/47899 * cfgloopmanip.c (fix_bb_placements): Fix first argument to flow_loop_nested_p when moving the loop upward. * gcc.dg/pr47899.c: New test. 2011-03-15 Richard Guenther <rguenther@suse.de> PR middle-end/48031 * fold-const.c (fold_indirect_ref_1): Do not create new variable-sized or variable-indexed array accesses when in gimple form. Modified: branches/gcc-4_5-branch/gcc/ChangeLog branches/gcc-4_5-branch/gcc/cfgloopmanip.c branches/gcc-4_5-branch/gcc/cp/ChangeLog branches/gcc-4_5-branch/gcc/cp/init.c branches/gcc-4_5-branch/gcc/fold-const.c branches/gcc-4_5-branch/gcc/testsuite/ChangeLog
Author: rguenth Date: Mon Apr 18 14:37:08 2011 New Revision: 172652 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172652 Log: 2011-04-18 Richard Guenther <rguenther@suse.de> Backported from 4.6 branch 2011-03-11 Jakub Jelinek <jakub@redhat.com> PR c++/48035 * init.c (build_zero_init_1): Extracted from build_zero_init. Add FIELD_SIZE argument, if non-NULL and field bit_position as not smaller than that, don't add that field's initializer. Pass DECL_SIZE as last argument to build_zero_init_1 for DECL_FIELD_IS_BASE fields. (build_zero_init): Use build_zero_init_1. * g++.dg/inherit/virtual8.C: New test. 2011-03-05 Zdenek Dvorak <ook@ucw.cz> PR rtl-optimization/47899 * cfgloopmanip.c (fix_bb_placements): Fix first argument to flow_loop_nested_p when moving the loop upward. * gcc.dg/pr47899.c: New test. 2011-03-15 Richard Guenther <rguenther@suse.de> PR middle-end/48031 * fold-const.c (fold_indirect_ref_1): Do not create new variable-sized or variable-indexed array accesses when in gimple form. Added: branches/gcc-4_5-branch/gcc/testsuite/g++.dg/inherit/virtual8.C branches/gcc-4_5-branch/gcc/testsuite/gcc.dg/pr47899.c
Jakub, shall we close this?
Will the fixes for this PR go into 4.4?
Author: jason Date: Thu Oct 13 18:02:53 2011 New Revision: 179937 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=179937 Log: PR c++/48035 * init.c (build_zero_init_1): Extracted from build_zero_init. Add FIELD_SIZE argument, if non-NULL and field bit_position as not smaller than that, don't add that field's initializer. Pass DECL_SIZE as last argument to build_zero_init_1 for DECL_FIELD_IS_BASE fields. (build_zero_init): Use build_zero_init_1. Added: branches/gcc-4_4-branch/gcc/testsuite/g++.dg/inherit/virtual8.C Modified: branches/gcc-4_4-branch/gcc/cp/ChangeLog branches/gcc-4_4-branch/gcc/cp/init.c branches/gcc-4_4-branch/gcc/testsuite/ChangeLog
Fixed for 4.4.7.