Bug 111864 - bad codegen with -O1
bad codegen with -O1
Status: CLOSED WONTFIX
Product: Red Hat Enterprise Linux 3
Classification: Red Hat
Component: gcc3 (Show other bugs)
3.0
ia64 Linux
medium Severity high
: ---
: ---
Assigned To: Jakub Jelinek
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2003-12-10 19:14 EST by Martin Sebor
Modified: 2007-11-30 17:06 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2007-10-19 15:32:13 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Martin Sebor 2003-12-10 19:14:02 EST
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4)
Gecko/20030624 Netscape/7.1 (ax)

Description of problem:
The attached program, reduced from our implementation of
std::basic_string, produces an error at runtime when optimized at -O.
It runs with no errors at -O0 or -O2 or -O3. The output shows that the
compiler generates code that corrupts the program data (in the member
function free_a()). Outlining the member function also eliminates the bug.

Version-Release number of selected component (if applicable):
gcc-3.2.3 20030502 (Red Hat Linux 3.2.3-20)

How reproducible:
Always

Steps to Reproduce:
Compile and run the program t.C below with gcc -O t.C -lsupc++ &&
./a.out. Observe the incorrect output.

extern "C" {
  int printf (const char*, ...);

  void* malloc (unsigned long);
  void free (void*);
}

struct rw_mutex
{
  void acquire () { }
  void release () { }
};

struct rw_guard
{
  rw_mutex *mutex_;

  rw_guard (rw_mutex &mutex): mutex_ (&mutex) {
    mutex_->acquire ();
  }

  ~rw_guard () { mutex_->release (); }
};

template <class T>
inline T dec (T &t, rw_mutex &mutex)
{
  rw_guard guard (mutex);
  return --t;
}

template <class T>
inline T dec (T &t, bool)
{
  static rw_mutex mutex;
  return dec (t, mutex);
}

template <class T> class S;

template <class T>
struct A
{
  int ref () const { return refs_ + 1; }

  void inc () {
    if (this != S<T>::a1 ())
      ++this->refs_;
  }

  long dec () {
    return this == S<T>::a1 () ? 1L : 1 + ::dec (refs_, mutex_);
  }

  T* data () { return (T*)(this + 1); }

  rw_mutex mutex_;

  int refs_;
  int cap_;
  int size_;
};

template <class T>
struct A1: A<T>
{
  T t;
};

template <class T>
struct S
{
  S (): data_ (a1 ()->data ()) { }

  S (const S&);

  S (const T*, int);

  ~S () {
    free_a (0);
  }

  S& foobar (const S&) { return *this; }

  S& append (const S&);

  A<T>* a0 () const {
    return (A<T>*)data_ - 1;
  }

  void free_a (T*);

  static A1<T>* a1 () {
    static A1<T> a;

    return &a;
  }

  A<T>* make_a0 (int, int);

  T* data_;
};


template <class T>
inline void S<T>::free_a (T* ptr)
{
  void* const a = a0 ();

  const long ref = a0 ()->dec ();

  if (0 >= ref) {

    printf ("free_a(): deallocating %p %c= %p)\n",
            a0 (), a0 () == a ? '=' : '!', a);

    free (a0 ());
  }

  data_ = ptr;
}

template <class T>
S<T>::S (const S<T> &s)
{
  if (s.a0 ()->ref () > 0) {
    data_ = s.data_;
    a0 ()->inc ();
  }
  else {
    const int n = s.a0 ()->size_;
    data_ = make_a0 (n, n)->data ();
  }
}

template <class T>
S<T>& S<T>::append (const S &str)
{
  const int len = a0 ()->size_ + str.a0 ()->size_;

  if (len > a0 ()->cap_ || a0 ()->ref () > 1)
    return foobar (str);

  return *this;
}

template <class T>
A<T>* S<T>::make_a0 (int cap, int len)
{
  if (!cap)
    return a1 ();

  A<T>* a = (A<T>*)malloc (cap + sizeof (A<T>) + 2);

  a->cap_  = cap;
  a->size_ = len;
  a->refs_ = 0;

  return a;
}

template <class T>
S<T>::S (const T* s, int n)
{
  data_ = make_a0 (128 <  n ? n : 128, n)->data ();
}

template <class T>
inline S<T> operator+ (const S<T> &lhs, const S<T> &rhs)
{
  return S<T>(lhs.data_, lhs.a0 ()->size_).append (rhs);
}

const S<char> s1 ("1", 1);

int main ()
{
  S<char>() + s1;
}


Actual Results:  When compiled at -O1, the output of the program is:
free_a(): deallocating 0x600000000002c840 == 0x600000000002c840)
free_a(): deallocating 0x600000000002c820 != 0x600000000002c830)
free(): invalid pointer 0x600000000002c820!
free_a(): deallocating 0x600000000002c7a0 == 0x600000000002c7a0)


Expected Results:  When compiled at -O0, the output of the program is:
free_a(): deallocating 0x600000000001d540 == 0x600000000001d540)
free_a(): deallocating 0x600000000001d4a0 == 0x600000000001d4a0)


Additional info:
Comment 1 Martin Sebor 2004-06-09 16:59:42 EDT
The problem was originally reported against 3.2.3-20. We continue to
experience it with gcc 3.2.3-24 (on Red Hat Advanced Server 3.0/IA64).
Has there been any progress at all on this issue?
Comment 2 Jakub Jelinek 2004-06-09 17:45:48 EDT
Verified this in g++ 3.2.3-35 and g++ 3.3.3-7, while it seems to work
with g++ 3.4.0-2 (as well as with -O0, -Os, -O2 and -O3).
Comment 3 RHEL Product and Program Management 2007-10-19 15:32:13 EDT
This bug is filed against RHEL 3, which is in maintenance phase.
During the maintenance phase, only security errata and select mission
critical bug fixes will be released for enterprise products. Since
this bug does not meet that criteria, it is now being closed.
 
For more information of the RHEL errata support policy, please visit:
http://www.redhat.com/security/updates/errata/
 
If you feel this bug is indeed mission critical, please contact your
support representative. You may be asked to provide detailed
information on how this bug is affecting you.

Note You need to log in before you can comment on or make changes to this bug.