Memory corruption is occurring due to codegen bug. Copying a data structure through a temporary returned by value from a function is corrupt. But copying directly is ok. The following conditions seem to need to be present: 1) the object ("Data") is an exact multiple of 64-bytes. Changing the size of Data::argv_ seems to fix the problem. 2) the object ("Data") uses the compiler supplied copy constructor. Supplying a copy ctor seems to fix the problem. 3) make_data() takes its parameter by value. Changing make_data() to take its argument by reference seems to fix the problem. 4) compile without optimizations. Compiling with -O3 seems to fix the problem. CODE: Program Output: a.out: /tmp/bug.cpp:51: int main(int, char**): Assertion `d2.argv_[0] == 'A'' failed. Aborted (core dumped) To reproduce: Save this file as bug.cpp, then compile with "g++ bug.cpp" --- While this is contrived code, the same problem occurs in real code using std::make_pair, which is what inspired this investigation. --- g++ -v -save-temps bug.cpp Reading specs from /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/specs Configured with: ./configure --prefix=/usr/local/gcc-3.2 --enable-threads --enable-languages=c,java Thread model: posix gcc version 3.2 /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/cpp0 -lang-c++ -D__GNUG__=3 -D__DEPRECATED -D__EXCEPTIONS -v -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=0 -D__GXX_ABI_VERSION=102 -D__ELF__ -Dunix -D__gnu_linux__ -Dlinux -D__ELF__ -D__unix__ -D__gnu_linux__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -D_GNU_SOURCE -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i686__ -D__tune_pentiumpro__ bug.cpp bug.ii GNU CPP version 3.2 (cpplib) (i386 Linux/ELF) ignoring nonexistent directory "/usr/local/gcc-3.2/i686-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/gcc-3.2/include/c++/3.2 /usr/local/gcc-3.2/include/c++/3.2/i686-pc-linux-gnu /usr/local/gcc-3.2/include/c++/3.2/backward /usr/local/include /usr/local/gcc-3.2/include /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/include 1 /usr/include End of search list. /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/cc1plus -fpreprocessed bug.ii -quiet -dumpbase bug.cpp -version -o bug.s GNU CPP version 3.2 (cpplib) (i386 Linux/ELF) GNU C++ version 3.2 (i686-pc-linux-gnu) compiled by GNU C version 3.2. as -V -Qy -o bug.o bug.s GNU assembler version 2.13.90.0.2 (i386-redhat-linux) using BFD version 2.13.90.0.2 20020802 /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/collect2 -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/crtbegin.o -L/usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2 -L/usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/../../.. bug.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/gcc-3.2/lib/gcc-lib/i686-pc-linux-gnu/3.2/crtend.o /usr/lib/crtn.o Release: g++ 3.2 Environment: RH linux 7.3 SMC. Intel dual P3/950 MHz How-To-Repeat: compile the following code with the command: "g++ bug.cpp" It's not preprocessed, but <cassert> is the only file included. #include <cassert> typedef unsigned int size_t; extern void *memset(void *s, int c, size_t n); extern char *strncpy(char *dest, const char *src, size_t n); struct Data { Data() { memset(argv_, '\0', sizeof(argv_)); } Data(char const * s) { strncpy (argv_, s, sizeof(argv_)); argv_[sizeof(argv_)-1] = '\0'; } char argv_[64]; }; // it does not matter if this is inline or not. inline Data make_data(Data y) { return y; } int main(int argc, char * argv[]) { // create a "prototype" object Data data("ABCDEF"); assert(data.argv_[0] == 'A'); // OK // direct copy works Data d1(data); assert(d1.argv_[0] == 'A'); // OK // copy temporary through helper function fails... Data d2( make_data(data) ); assert(d2.argv_[0] == 'A'); // fail }
State-Changed-From-To: open->analyzed State-Changed-Why: Confirmed. This used to work until 3.0, but fails with 3.2, 3.3 and 3.4. I'd think that this is a serious regression, being a wrong-code failure. To get rid of the string functions, here's a very slightly modified testcase that still fails: ---------------------------------#include <cassert> struct C { C(char const * s) { for (int i=0; i<sizeof(p); ++i) p[i]=s[i]; } char p[64]; }; inline C make_c(C y) { return y; } int main(int argc, char * argv[]) { C data("ABCDEF"); assert(data.p[0] == 'A'); // OK C d1(data); assert(d1.p[0] == 'A'); // OK C d2( make_c(data) ); assert(d2.p[0] == 'A'); // fail } ------------------------------ W.
State-Changed-From-To: analyzed->closed State-Changed-Why: fixed with http://gcc.gnu.org/ml/gcc-patches/2003-02/msg00702.html