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 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.)

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)

So your example contains undefined behaviour even without considering the
parts of 6.5 clause 7 that you quoted.




Moreover I think you are misinterpreting 6.5 clause 7 (which I concede is
fairly easy since it is not quite as unambiguous as one could wish).
I believe that paragraph should not be interpreted as automatically allowing
all accesses that correspond to one of the sorts listed.  Rather it should
be interpreted as saying that if an access is not included in that list then
it is not allowed, but even if it is included in that list there could be
other reasons why it is not allowed.  (I.e.  just as the attached footnote
suggests it is a list of what types of aliasing are allowed, not of which
pointers may be dereferenced.)


As for the purpose of the part you quoted above (about aggregate and union
types) I believe it is intended for the following situation:

 struct S1 {
 int x;
 int y;
 double z;
 };

 struct S2 {
 float f1;
 float f2;
 };

 void foo(struct S1 *p1, int *a)
	{

 ...

	}

 void bar(struct S2 *p2, int *b)
	{

 ...


	}



Here 6.5 clause 7 says that (inside the functions depicted) it is possible
that accessing the object '*p1' also accesses the object '*a' while it is
guaranteed that accessing '*p2' will not access '*b', since '*p1' is an
aggregate type containing a member of the same type as '*b', while '*p2' is
an aggregate type not containing a member of the same type as '*b'.

Moreover accessing (*p1).x) or (*p1).y might also access '*a' (since the type
of '(*p1).x' is compatible with the type of '*a'), but an access to
'(*p1).z' will not access '*a'.

(The obvious situation where accessing *p1 would also access *a is if foo() is
called as follows:

 struct S1 A;

 foo(&A, &(A.x));

)

-- 
<Insert your favourite quote here.>
Erik Trulsson
ertr1013@student.uu.se


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