This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]