Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this hack to remove aliasing warning UB?

We just upgraded our compiler to gcc 4.6 and now we get some of these warnings. At the moment our codebase is not in a state to be compiled with c++0x and anyway, we don't want to run this in prod (at least not yet) - so I needed a fix to remove this warning.

The warnings occur typically because of something like this:

struct SomeDataPage
{
  // members
  char vData[SOME_SIZE];
};

later, this is used in the following way

SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor

To read, update and return for example, the following cast used to happen

reinterpret_cast<SomeType*>(page.vData)->some_member();

This was okay with 4.4; in 4.6 the above generates:

warning: type punned pointer will break strict-aliasing rules

Now a clean way to remove this error is to use a union, however like I said, we can't use c++0x (and hence unrestricted unions), so I've employed the horrible hack below - now the warning has gone away, but am I likely to invoke nasal daemons?

static_cast<SomeType*>(reinterpret_cast<void*>(page.vData))->some_member();

This appears to work okay (see simple example here: http://www.ideone.com/9p3MS) and generates no warnings, is this okay(not in the stylistic sense) to use this till c++0x?

NOTE: I don't want to use -fno-strict-aliasing generally...

EDIT: It seems I was mistaken, the same warning is there on 4.4, I guess we only picked this up recently with the change (it was always unlikely to be a compiler issue), the question still stands though.

EDIT: further investigation yielded some interesting information, it seems that doing the cast and calling the member function in one line is what is causing the warning, if the code is split into two lines as follows

SomeType* ptr = reinterpret_cast<SomeType*>(page.vData);
ptr->some_method();

this actually does not generate a warning. As a result, my simple example on ideone is flawed and more importantly my hack above does not fix the warning, the only way to fix it is to split the function call from the cast - then the cast can be left as a reinterpret_cast.

like image 214
Nim Avatar asked Sep 20 '11 10:09

Nim


2 Answers

SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor
reinterpret_cast<SomeType*>(page.vData)->some_member();

This was okay with 4.4; in 4.6 the above generates:

warning: type punned pointer will break strict-aliasing rules

You can try:

SomeDataPage page;
SomeType *data = new(page.vData) SomeType(); // non-trivial constructor
data->some_member();
like image 97
curiousguy Avatar answered Nov 13 '22 11:11

curiousguy


Why not use:

SomeType *item = new (page.vData) SomeType();

and then:

item->some_member ();

I don't think a union is the best way, it may also be problematic. From the gcc docs:

`-fstrict-aliasing'
 Allows the compiler to assume the strictest aliasing rules
 applicable to the language being compiled.  For C (and C++), this
 activates optimizations based on the type of expressions.  In
 particular, an object of one type is assumed never to reside at
 the same address as an object of a different type, unless the
 types are almost the same.  For example, an `unsigned int' can
 alias an `int', but not a `void*' or a `double'.  A character type
 may alias any other type.

 Pay special attention to code like this:
      union a_union {
        int i;
        double d;
      };

      int f() {
        a_union t;
        t.d = 3.0;
        return t.i;
      }
 The practice of reading from a different union member than the one
 most recently written to (called "type-punning") is common.  Even
 with `-fstrict-aliasing', type-punning is allowed, provided the
 memory is accessed through the union type.  So, the code above
 will work as expected.  However, this code might not:
      int f() {
        a_union t;
        int* ip;
        t.d = 3.0;
        ip = &t.i;
        return *ip;
      }

How this relates to your problem is tricky to determine. I guess the compiler is not seeing the data in SomeType as the same as the data in vData.

like image 1
Skizz Avatar answered Nov 13 '22 10:11

Skizz