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