Bug 105689 - Bogus `-Wstringop-overflow=` after accessing field, then containing struct (wrong "region size")
Summary: Bogus `-Wstringop-overflow=` after accessing field, then containing struct (w...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: diagnostic
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
Reported: 2022-05-22 11:30 UTC by sagebar
Modified: 2023-05-17 21:00 UTC (History)
4 users (show)

See Also:
Known to work:
Known to fail: 11.2.0, 12.1.0
Last reconfirmed: 2023-05-17 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description sagebar 2022-05-22 11:30:51 UTC
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; }

======= 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>)`)
Comment 1 Richard Biener 2022-05-23 07:30:44 UTC
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?
Comment 2 Martin Sebor 2022-05-23 20:27:05 UTC
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.
Comment 3 Andrew Pinski 2023-05-17 20:56:04 UTC
Comment 4 Andrew Pinski 2023-05-17 21:00:22 UTC
I thought we had another bug for this CSEing ...