Does the following code invoke undefined behavior (due to aliasing violation or otherwise)?
int foo(int (*a)[10], int (*b)[5])
{
(*a)[5]++;
return (*b)[0];
}
int x[10];
foo(&x, (int (*)[5])&x[5]);
Note that the corresponding code using plain int *
rather than pointer-to-array types would be perfectly legal, because a
and b
would be pointers to the same type and thus allowed to alias one another.
Edit: The interesting consequence, if this is in fact an aliasing violation, is that it seems to be a hackish but valid way to get restrict
semantics pre-C99. As in:
void some_func(int *aa, int *bb)
{
int (*a)[1] = (void *)aa;
int (*b)[2] = (void *)bb;
/* Now **a and **b can be assumed by the compiler not to alias */
}
Presumably if you needed to access an actual array at each address, you could use SIZE_MAX-1 and SIZE_MAX-2 etc. as the differing sizes.
Two seemingly different pointers may point to storage locations in the same array (aliasing). As a result, data dependencies can arise when performing loop-based computations using pointers, as the pointers may potentially point to overlapping regions in memory.
"Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias each other.)"
In both C and C++ the standard specifies which expression types are allowed to alias which types. The compiler and optimizer are allowed to assume we follow the aliasing rules strictly, hence the term strict aliasing rule.
In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.
You are not accessing objects through pointers of different type here: you are not manipulating the array objects to which a
and b
point themselves but the objects pointed to by (*a)+5
and (*b)+0
, namely *((*a)+5)
and *((*b)+0)
. Since these are pointers to the same type they may well alias to the same object.
The implicit assignment by the ++
operator is a valid assignment to the object pointed to by (*b)+0
: ++
is equivalent to x = x + 1
(besides x
being evaluated only once) and for simple assignment =
the standard says
If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.
The types here are exactly the same and the overlap is exact.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With