Bug 9297 - [3.2/3.3/3.4 regression] data corruption due to codegen bug (when copying.)
Summary: [3.2/3.3/3.4 regression] data corruption due to codegen bug (when copying.)
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.2
: P1 critical
Target Milestone: 3.1.x/3.2.x
Assignee: Alan Modra
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2003-01-13 08:16 UTC by chris
Modified: 2004-08-25 17:26 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description chris 2003-01-13 08:16:01 UTC
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
}
Comment 1 Wolfgang Bangerth 2003-01-21 22:05:21 UTC
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.
Comment 2 Alan Modra 2003-02-23 22:51:44 UTC
State-Changed-From-To: analyzed->closed
State-Changed-Why: fixed with http://gcc.gnu.org/ml/gcc-patches/2003-02/msg00702.html