Bug 11915

Summary: Aliasing problems with user-defined operator new
Product: gcc Reporter: Andreas Glowatz <Andreas.Glowatz>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: arno, gcc-bugs, rasmus.bonnedal
Priority: P2 Keywords: wrong-code
Version: 3.3.1   
Target Milestone: 3.4.0   
Host: i686-linux-gnu Target: i686-linux-gnu
Build: i686-linux-gnu Known to work:
Known to fail: Last reconfirmed:
Attachments: single C++ source file, ii file and g++ -v -save-temps output

Description Andreas Glowatz 2003-08-14 07:47:27 UTC
If a small piece of C++ code is compiled with "-O2 -frename-registers", instead of
"-O", the resulting executable will not work correct.
Comment 1 Andreas Glowatz 2003-08-14 07:51:54 UTC
Created attachment 4603 [details]
single C++ source file, ii file and g++ -v -save-temps output
Comment 2 Andreas Glowatz 2003-08-14 07:59:12 UTC
I noticed this wrong behaviour since version 3.3. In version 3.2.1, it seems to
be ok.
Comment 3 Andrew Pinski 2003-08-14 13:33:39 UTC
I can confirm this on the mainline but I think you are violating aliasing rules (confirmed but also 
using -fno-strict-alasing and running the program).
Comment 4 Wolfgang Bangerth 2003-08-14 14:21:41 UTC
I'm not sure that this is really an aliasing problem. The only casts that happen in the 
program involve char*s. I'd like an aliasing expert to look at this first. 
 
W. 
Comment 5 Andreas Glowatz 2003-08-14 14:29:36 UTC
I tried using "-O3 -fno-strict-aliasing" and it seems to be ok, now. Is this the
solution, or is there any more.
Comment 6 Volker Reichelt 2003-08-15 18:41:15 UTC
Here's a reduced testcase.

It returns 1 when compiled with "g++ -O2" and
0 when compiled with "g++ -O2 -fno-strict-aliasing":

================================================
char Pool[32];

struct A { A* next; };
A* a=0;

struct B
{
    void* p;
    B() : p((void*)4711) {}

    void* operator new(unsigned)
    {
        if (!a) a = (A*)Pool;
        A* q = a;
        a = a->next;
        return q;
    }
};

int main ()
{
    new B;
    return a == (void*)4711;
}
================================================

I'm not sure whether this example violates aliasing rules,
but it's an aliasing problem nevertheless. I updated the
summary accordingly.
Comment 7 Andrew Pinski 2003-08-18 22:48:24 UTC
This looks like an almost exact dup of bug 11973.
From that bug:
Your code is invalid. What you do is this: 
- in new a->X_alc() you call C::operator new, which returns a C* which you later access 
- however, C::operator new calls alc(), which returns the memory location of an object 
  which the compiler assumes is of type SList 
Such type games violate C++'s type aliasing rules. The solution is either to fix your 
code, or if you want to play hide-and-seek with the compiler, use -fno-strict-aliasing. 

The names of the functions are different but the game is the same.

*** This bug has been marked as a duplicate of 11973 ***
Comment 8 Wolfgang Bangerth 2003-08-18 23:18:54 UTC
I'd like to reopen this bug report again, for the same reason as before: here we are 
only dealing with char*, which is special. We still need to have someone with 
more knowledge of aliasing rules here. 
 
W. 
Comment 9 Yuri 2003-08-19 00:46:06 UTC
Simple situation:
If function is not inlined it works correct.
If function is inlined it swaps 2 operations across
this function and the calling one (operator new).

Inlining should NEVER change net result in such cases.

What's wrong with this code exactly ?

Yuri (yuri@tsoft.com)
Comment 10 Kriang Lerdsuwanakij 2003-08-24 15:30:51 UTC
Not a bug.  The provided testcase violate alias rules.
The compiler assume that the two pointers, 'this'
and 'a' in
  this->p = 4711  (inside constructor)
and
  a = a->next  (inside new operator)
point to different object, which is not true in your code.
Comment 11 Andrew Pinski 2004-04-02 12:30:44 UTC
*** Bug 14822 has been marked as a duplicate of this bug. ***
Comment 12 Giovanni Bajo 2004-04-02 14:22:30 UTC
Confirmed again to be invalid. What happens here is that the underlying char[] 
is accessed first through a A* (within operator new) and later through a B* (in 
B's constructor). This is equivalent to:

float foo(void)
{
  char buf[64];
  int* p1 = (int*)buf;
  float* p2 = (float*)buf;
  *p1 = 123;
  return *p2;
}

This code breaks aliasing rules (confirmed by Segher Boessenkool and Paul 
Brook), so the whole PR is invalid.
Comment 13 Andrew Pinski 2004-05-05 12:41:29 UTC
*** Bug 15295 has been marked as a duplicate of this bug. ***
Comment 14 Andrew Pinski 2005-06-05 08:45:14 UTC
Reopening to ...
Comment 15 Andrew Pinski 2005-06-05 08:45:31 UTC
Mark as a dup of bug 21920.

*** This bug has been marked as a duplicate of 21920 ***