https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105689

            Bug ID: 105689
           Summary: Bogus `-Wstringop-overflow=` after accessing field,
                    then containing struct (wrong "region size")
           Product: gcc
           Version: 12.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sagebar at web dot de
  Target Milestone: ---

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

Reply via email to