This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

optimization/7560: copy construction (return value optimization?)


>Number:         7560
>Category:       optimization
>Synopsis:       copy construction (return value optimization?)
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 09 09:56:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Brad Spencer
>Release:        gcc-3.1 and gcc-3.1.1
>Organization:
>Environment:
sparc64-sun-solaris2.8
>Description:
I'm using both gcc-3.1 [cross and native] and gcc-3.1.1 [cross] for the sparc64-sun-solaris2.8 target.  This bug only shows up when build 64-bit sparc targets AFAIK.

starbug:/starbug/spencer$ /opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -v
Reading specs from /opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1.1/specs
Configured with: ../../gcc-3.1.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/sparc64-sun-solaris2.8/target-stuff/include/ --with-lib=/opt/gcc-3.1.1-cross/sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1.1

starbug:/starbug/spencer$ /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -v
Reading specs from /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1-cross-sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/target-stuff/include/ --with-lib=/starbug/spencer/devel/gcc-cross/target-stuff/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1

netra-1:~$ /opt/gcc-3.1/bin/g++ -v        
Reading specs from /opt/gcc-3.1/lib/gcc-lib/sparc-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --with-gnu-as --with-gnu-ld --with-as=/opt/bin/as --with-ld=/opt/bin/ld --prefix=/opt/gcc-3.1
Thread model: single
gcc version 3.1

When running the following code compiled with any of these three compilers with optimizations on, the output is incorrect (see comments).  What I suspect is happening is that the m_container member of Container::iterator is being  treated as if it was only 32-bit during some optimization.  

Here is the code sample:

+++BEGIN
//*****************************************************************************
// Shows bug when compiled with gcc-3.1 or gcc-3.1.1 at -O2 or higher for
// sparc64-sun-solaris2.8.
//
// When compiled with -O or no optimizations, gives correct output:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ 
//   -Wall -o optfoo optfoo.cc -O
//  *** begin: [0xffffffff7ffff9bf, 0, 0] end: [0xabcd, 123456, 1]
//  Not equal
//
// But when build with -O2 or higher, gives incorrect output:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ 
//   -Wall -o optfoo optfoo.cc -O2
//  *** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 0, 0]
//  equal
//
// Removing the const qualifier from the two const members of iterator also
// avoids the bug, even on -O6:
// /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ 
//   -Wall -o optfoo optfoo.cc -O2 -DFOO_NO_CONST_MEMBERS
//  *** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 123456, 1]
//  Not equal


#include <iostream>
#include <iterator>
#include <string>

// If FOO_NO_CONST_MEMBERS is set, then skip the const on the iterator members
#if FOO_NO_CONST_MEMBERS
# define DEBUG_CONST
#else
# define DEBUG_CONST const
#endif

//=============================================================================

using std::cout;
using std::endl;

class Container
{
public:
  class iterator
  {
    // Not allowed
    void operator=(const iterator &);
    
  public:
    // creates as 'end'
    iterator()
      : m_container((Container *)0xABCD), m_all(true), m_idx(123456)
    {}
    
    bool operator!=(const iterator &rhs) const
    {
      return m_idx != rhs.m_idx;
    }

    // Return the packet itself
    const Container *getContainer() const { return m_container; }
    
    unsigned int getIdx() const { return m_idx; }
    bool getAll() const { return m_all; }
    
  protected:
    friend class Container;
    
    iterator(const Container *p,unsigned int i)
      : m_container(p), m_all(false), m_idx(i) {}
    
    explicit iterator(const Container *p)
      : m_container(p), m_all(true), m_idx(0) {}
    
    bool isValid() const {
      return m_container!=NULL;
    }
    
  private:
    const Container * DEBUG_CONST m_container;
    DEBUG_CONST bool m_all;
    unsigned int m_idx;
  };

  iterator get() const { return iterator(this, 1); }
  iterator begin() const { return iterator(this, 0); }
  iterator end() const { return iterator(); }
};

template<typename directly_supported_type,
  typename attribute_tag>
class DirectSupportIterator
  : public Container::iterator,
    public std::iterator<std::forward_iterator_tag, directly_supported_type>
{
private:
  // :: --------------------------------------------------------------------
  // :: Type Information
  
  typedef Container::iterator BaseClass;
  
public:
  // The value we dereference into
  typedef directly_supported_type value_type;
  
public:
  // :: --------------------------------------------------------------------
  // :: Construction

  // Copy construct from base class
  DirectSupportIterator(const BaseClass &it)
    : BaseClass(it)
  {}
  
  // Make "end" version
  DirectSupportIterator()
    : BaseClass()
  {}
  
  // Default copy and assignemnt
  
};

typedef int SomeType;
typedef DirectSupportIterator<std::string, SomeType> IteratorType;

class Wrapper
{
  Container p;
public:
  IteratorType begin() const { return p.begin(); }
  static IteratorType end() { return IteratorType(); }
};


int
main()
{
  std::ios::sync_with_stdio(false);

  Wrapper w;
  IteratorType begin = w.begin();
  const IteratorType end = Wrapper::end();

  cout << "*** begin: ["
       << begin.getContainer() << ", " << begin.getIdx()
       << ", " << begin.getAll() << "] end: ["
       << end.getContainer() << ", " << end.getIdx()
       << ", " << end.getAll() << ']' << std::endl;
  
  
  // Avoid logging if this field is not present
  if(begin != end) {
    cout << "Not equal" << endl;
  } else {
    cout << "equal" << endl;
  }
  
  return 0;
}
+++END


[ - - - ]

Here it is being built by gcc-3.1.1 (a cross compiler):

starbug:/starbug/spencer$ /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/bin/sparc64-sun-solaris2.8-g++ -Wall -o optfoo optfoo.cc -O2 -v
Reading specs from /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/specs
Configured with: ../gcc-3.1/configure --with-dwarf2 --enable-languages=c,c++ --enable-threads=single --disable-shared --prefix=/opt/gcc-3.1-cross-sparc64-sun-solaris2.8 --target=sparc64-sun-solaris2.8 -v --with-headers=/starbug/spencer/devel/gcc-cross/target-stuff/include/ --with-lib=/starbug/spencer/devel/gcc-cross/target-stuff/lib --with-gnu-as --with-gnu-ld --disable-multilib
Thread model: single
gcc version 3.1
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/cc1plus -v -D__GNUC__=3 -D__GNUC_MINOR__=1 -D__GNUC_PATCHLEVEL__=0 -Dsparc -Dsun -Dunix -D__svr4__ -D__SVR4 -D__PRAGMA_REDEFINE_EXTNAME -D__sparc__ -D__sun__ -D__unix__ -D__svr4__ -D__SVR4 -D__PRAGMA_REDEFINE_EXTNAME -D__sparc -D__sun -D__unix -Asystem=unix -Asystem=svr4 -D__OPTIMIZE__ -D__STDC_HOSTED__=1 -D_XOPEN_SOURCE=500 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__EXTENSIONS__ -D__SIZE_TYPE__=long unsigned int -D__PTRDIFF_TYPE__=long int -D__WCHAR_TYPE__=int -D__WINT_TYPE__=int -D__arch64__ -Acpu=sparc64 -Amachine=sparcv9 -D__sparcv9 optfoo.cc -D__GNUG__=3 -D__DEPRECATED -D__EXCEPTIONS -D__GXX_ABI_VERSION=100 -quiet -dumpbase optfoo.cc -O2 -Wall -version -o /var/tmp//ccWZmCh0.s
GNU CPP version 3.1 (cpplib) (sparc ELF)
GNU C++ version 3.1 (sparc64-sun-solaris2.8)
        compiled by GNU C version 3.1.
ignoring nonexistent directory "/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3/sparc64-sun-solaris2.8
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include/g++-v3/backward
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/include
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/include
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/sparc64-sun-solaris2.8/sys-include
End of search list.
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/../../../../sparc64-sun-solaris2.8/bin/as -V -Qy -s -64 -Av9 -o /var/tmp//cc1scFwK.o /var/tmp//ccWZmCh0.s
GNU assembler version 2.11.2 (sparc64-sun-solaris2.8) using BFD version 2.11.2
 /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/collect2 -V -Y P,/usr/lib/sparcv9 -Qy -o optfoo /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crt1.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crti.o /usr/lib/sparcv9/values-Xa.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtbegin.o -L/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1 -L/opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/../../../../sparc64-sun-solaris2.8/lib /var/tmp//cc1scFwK.o -lstdc++ -lm -lgcc -lc -lgcc -lc /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtend.o /opt/gcc-3.1-cross-sparc64-sun-solaris2.8/lib/gcc-lib/sparc64-sun-solaris2.8/3.1/crtn.o
GNU ld version 2.11.2 (with BFD 2.11.2)
  Supported emulations:
   elf64_sparc
   elf32_sparc

[ - - - ]

The expected output is of the form (the first pointer value is understandably different):

netra-1:~$ /starbug/spencer/optfoo 
*** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 123456, 1]
Not equal

Here is a -O2 compiled version being run on a sparc64-sun-solaris2.8 box:

netra-1:~$ /starbug/spencer/optfoo 
*** begin: [0xffffffff7ffff9cf, 0, 0] end: [0xabcd, 0, 0]
equal

The begin object is usually right during the failure, but the end object is always incorrect.  As is suggested by the code comments, turning off -O2 or removing the two const qualifiers on Container::iterator's members avoids this bug.

I suspect that this is the "return value optimization" acting up.  I could not find a compiler option to turn off just this optimization.
>How-To-Repeat:
See description.
>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]