The following code wrongly produces a warning `[-Wstringop-overflow=`: Compile (using `gcc -c -O2 infile.c`) ``` struct subobject { int field1; int field2; }; struct myobject { struct subobject sub; }; extern void access_1(int *a); extern __attribute__((access(read_write, 1))) void access_2(struct subobject *); void myfunc(struct myobject *me) { // { void *p __attribute__((unused)) = &me->sub; } access_1(&me->sub.field1); access_2(&me->sub); } ``` ======= Output (gcc-12) ======= >infile.c: In function 'myfunc': >infile.c:16:9: warning: 'access_2' accessing 8 bytes in a region of size 4 [-Wstringop-overflow=] > 16 | access_2(&me->sub); > | ^~~~~~~~~~~~~~~~~~ >infile.c:11:52: note: in a call to function 'access_2' declared with attribute 'access (read_write, 1)' > 11 | extern __attribute__((access(read_write, 1))) void access_2(struct subobject *); > | ^~~~~~~~ ======= Output (expected) ======= ><No warning> ======= Notes ======= - By uncommenting the line `{ void *p __attribute__((unused)) = &me->sub; }`, the warning goes away, even though that line literally does nothing. (see Theory below) - I was able to observe this bug in gcc-12.1.0 and gcc-11.2.0 ======= Theory ======= It seems that this has got something to do with some internal, hidden attribute (relating to the "region size") attached to some field-expression the first time that field is accessed, only that when accessing `me->sub.field1` (where `offsetof(field1) == 0`) before `me->sub`, that "region size" attribute wrongfully also gets attached to `me->sub`. Then, when an access to `me->sub` actually happens, gcc seems to think that the "region size" of `me->sub` as a whole matches the size of the previously accessed field (`me->sub.field1`). This seems further compounded by the fact that this only happens when `field1` is the first field of `subobject` (i.e. has offset 0). If we insert another field `int field0;` before it, the warning also disappears (so something in gcc's logic appears to make it think that `region_size_of(<field-at-offset-0>) == region_size_of(<containing-struct>)`)
It's likely triggered by us CSEing &me->sub.field1 and &me->sub but I don't know how that changes whether a diagnostic happens or not. Hmm, IIRC there's some magic going on at the frontend which attaches some further attributes which then _might_ get confused with such CSE. Martin, do you remember off-head how such CSE might impact the diagnostics?
It is because of CSE. The warning sees this IL: _1 = &me_3(D)->sub.field1; access_1 (_1); access_2 (_1); and so it warns for the second call because the size of me->sub.field1 passed to it is smaller than struct subobject. The attribute access on access_2() is what tells it to use the size of struct subobject. The CSE substitution causes false positives in other contexts besides calls to functions with attribute access. IIRC, one of the ideas for dealing with this we discussed was to have CSE use the largest subobject instead whatever it comes across first.
Confirmed.
I thought we had another bug for this CSEing ...