Assume we have the following code:
typedef struct {
int f1;
int f2;
} t_str;
int f(t_str* p, t_str* q)
{
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
return 0;
}
When we compile it (I used gcc-5.1.0) with -O3 option, the compiler gets the following assembler:
f:
.LFB0:
.cfi_startproc
movl 8(%esp), %edx
movl 4(%esp), %ecx
movl 4(%edx), %eax
addl $9, (%ecx)
addl $9, %eax
movl %eax, 4(%edx)
xorl %eax, %eax
ret
.cfi_endproc
That means that gcc decided access to field f1 of p and access to field f2 of q never alias. I guess this comes from assume that two objects of the same type never overlaps or they are the same. But I didn't find the issue in standard.
So please, can anyone find this issue in standard, or another point why gcc restricted field access, or comment what happened?
UPD:
Well, I thought about Paragraph 7 of Section 6.5 too, but it would be more comfortable for me to have something like that in explicit form for all objects:
6.5.16.1 Simple assignment
3 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.
Unfortunately this rule can not be used here.
Now look, if for code above I make the following function:
void main()
{
char * c = malloc(12);
memset(c, 0, 12);
f((t_str *)(c + 4), (t_str *)c);
printf("%d %d %d\n", ((t_str *)c)->f1, ((t_str *)c)->f2, ((t_str *)(c + 4))->f2);
}
Now I get the following during execution:
$ gcc-5.1.0 test1.c -O3 && ./a.out
0 9 0
$ gcc-5.1.0 test1.c -O0 && ./a.out
0 18 0
So how do you think is this code valid? Because I'm not shure if it statisfy Paragraph 7 of Section 6.5.
PS: interesting thing:
$ gcc-5.1.0 test1.c -O3 -fwhole-program && ./a.out
0 10 0
$ gcc-5.1.0 test1.c -O3 -flto && ./a.out
0 10 0
Paragraph 7 of Section 6.5 of the latest draft (N1570) of C11 reads:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88) — a type compatible with the effective type of the object, — a qualified version of a type compatible with the effective type of the object, — a type that is the signed or unsigned type corresponding to the effective type of the object, — a type that is the signed or unsigned type corresponding to a qualified version of 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 — a character type.
I interpret this to mean that objects pointed to by p
and q
cannot overlap unless they are the same object, because the t_str
objects are supposed to be accessed by proper pointers.
The Standard is not precise enough to make it clear that &p->f2
is not a valid pointer to a t_str
object composed of 2 int
shared between p[0]
and p[1]
. Yet it seems incorrect because the compiler could possibly insert padding between f1
and f2
or indeed between f2
and the end of the structure.
Incidentally, &p->f2 - &p->f1
is not a valid expression because paragraph 9 of section 6.5.6 Additive operators states this constraint: When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object;
If function f()
took a pointer to char
as parameter and accessed data via this pointer, gcc
could not assume this data to be distinct from the int
members of the structures pointed to by p
and q
. This somewhat counterintuitive exception is the reason why so many C library function prototypes have restrict
qualifiers on many pointer arguments. (These qualifiers in function prototypes are merely a hint to the programmer, but do not really tell the compiler anything).
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