help with g++ and strict aliasing on x86-64

Andrew Haley aph@redhat.com
Mon Nov 22 18:12:00 GMT 2010


On 11/22/2010 04:41 PM, Alberto Griggio wrote:
> Hello,
> I'm having trouble understanding what I'm doing wrong in the following piece 
> of code. 
> 
> My OS is Debian GNU/Linux 5.0, compiler is
> g++-4.1 (GCC) 4.1.3 20080704 (prerelease) (Debian 4.1.2-25)
> platform x86-64
> 
> The following code results in abort() being called (sorry if it's a bit 
> long, but this is the smallest example I could come up with):
> 
>   #include <new>
>   #include <stdlib.h>
>   #include <assert.h>
>   #include <stdio.h>
>   
>   struct Link { Link *next_; }; // __attribute__((__may_alias__));
>   struct Foo { void *value; };
>   
>   struct Alloc {
>       Alloc() { head_ = NULL; }    
>       ~Alloc() {}
>   
>       void *allocate()
>       {
>           static int cnt = 0;
>           if (head_ == NULL) {
>               if (cnt++) { abort(); }
>   
>               Link *mem = static_cast<Link *>(malloc(sizeof(Link) * 3));
>               head_ = new (mem) Link;
>               Link *last = head_ + 2;
>               for (Link *p = head_; p < last; ++p) {
>                   Link *next = new (p+1) Link;
>                   p->next_ = next;
>               }
>               last->next_ = NULL;
>           }
>           Link *p = head_;
>           head_ = p->next_;
>           p->~Link();
>           return static_cast<void *>(p);
>       }
>           
>       Link *head_;
>   };
>   
>   struct FooAlloc {
>       Foo *alloc() { return new (p_.allocate()) Foo(); }
>       Alloc p_; 
>   };
>   
>   int main()
>   {
>       if (sizeof(Foo) != sizeof(Link)) { abort(); }
>       printf("here\n"); fflush(stdout);
>       
>       FooAlloc pool;
>       Foo *e = pool.alloc();
>       if (e) {
>           printf("e\n"); fflush(stdout);
>       }
>       e = pool.alloc();
>       return 0;
>   }
> 
> 
> If I uncomment the "may_alias" attribute, everything works. But I don't 
> quite understand why "may_alias" is needed here. Could somebody help please? 
> My understanding is that, since in Alloc::allocate() I'm calling the 
> destructor of p before returning a pointer to the memory in which it is 
> allocated, and in FooAllo::alloc() I'm constructing a new object in that 
> memory area, aliasing should not be an issue.

It's much simpler than that.

Here you have a Link* :

           Link *p = head_;
           head_ = p->next_;
           p->~Link();
           return static_cast<void *>(p);

and you cast it to a Foo* :

       Foo *e = pool.alloc();

Foo and Link are not compatible types.  You cannnot take a pointer to
a Link and alias it to a pointer to a Foo.

Your problem is these two casts.  gcc doesn't spot the problem because
you're going via void*.

Andrew.



More information about the Gcc-help mailing list