This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: GCC aliasing rules: more aggressive than C99?
On 01/06/2010 04:09 AM, Joshua Haberman wrote:
> Erik Trulsson <ertr1013 <at> student.uu.se> writes:
>> On Sun, Jan 03, 2010 at 05:46:48AM +0000, Joshua Haberman wrote:
>>> The aliasing policies that GCC implements seem to be more strict than
>>> what is in the C99 standard. I am wondering if this is true or whether
>>> I am mistaken (I am not an expert on the standard, so the latter is
>>> definitely possible).
>>> -
>>> The relevant text is:
>>> -
>>> An object shall have its stored value accessed only by an lvalue
>>> expression that has one of the following types:
>>> -
>>> * a type compatible with the effective type of the object,
>>> [...]
>>> * an aggregate or union type that includes one of the aforementioned
>>> types among its members (including, recursively, a member of a
>>> subaggregate or contained union), or
>>> -
>>> To me this allows the following:
>>> -
>>> int i;
>>> union u { int x; } *pu = (union u*)&i;
>>> printf("%d\n", pu->x);
>>> -
>>> In this example, the object "i", which is of type "int", is having its
>>> stored value accessed by an lvalue expression of type "union u", which
>>> includes the type "int" among its members.
>> -
>> Even with your interpretation of the C99 standard that example would be
>> allowed only if '*pu' is a valid lvalue of type 'union u'. (Since pu->x
>> is equivalent to (*pu).x)
>> -
>> First of all the conversion (union u*)&i is valid only if the alignment
>> of 'i' is suitable for an object of type 'union u'. Lets assume that is the
>> case. (Otherwise just making that conversion would result in undefined
>> behaviour.) (See 6.3.2.3 clause 7.)
>
> This is true. You could get around this particular point by saying:
>
> int *i = malloc(sizeof(*i));
> *i = 5;
> union u { int x; } *pu = (union u*)i;
> printf("%d\n", pu->x);
>
> ...since the return from malloc() is guaranteed to be suitably aligned for
> any object (7.20.3). But your point is taken.
>
>> There is however no guarantee that the conversion yields a valid
>> "pointer to union u". If not then dereferencing it (with the
>> expression '*pu') has undefined behaviour. (See 6.5.3.2 clause 4)
>
> I think this is a bit of a stretch. It is true that 6.5.3.2 says that
> dereferencing invalid values has undefined behavior. But if you are
> saying that the standard has to explicitly say that a pointer conversion
> will not result in an invalid value (even when suitably aligned), then
> the following is also undefined:
>
> int i;
> unsigned int *pui = (unsigned int*)&i;
> unsigned int ui = *pui;
>
> Andrew cited 6.3.2.3p2 as support for why this is defined, but that
> paragraph deals with qualifiers (const, volatile, and restrict).
> "unsigned" is not a qualifier.
You are correct, and I was completely wrong about this. I thought you
were talking about qualifiers: I didn't read what you'd written
carefully enough and I responded too quickly.
> There is no part of the standard that guarantees that a pointer
> conversion from "int*" to "unsigned int*" will not result in an
> invalid value.
That's right.
Andrew.