Bug 105805 - -fstrict-volatile-bitfields can read beyond the end of the bitfield group
Summary: -fstrict-volatile-bitfields can read beyond the end of the bitfield group
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks: 114371
  Show dependency treegraph
 
Reported: 2022-06-01 16:28 UTC by Richard Sandiford
Modified: 2024-03-18 05:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Sandiford 2022-06-01 16:28:42 UTC
There are a few PRs related to -fstrict-volatile-bitfields, but this
one didn't seem to be a dup.

For:

-----------------------------------------------------------
struct S1 { volatile int a : 16; } __attribute__((packed));
struct S2 { _Alignas(4) struct S1 b; volatile short c; };
_Static_assert (sizeof (struct S2) == 4);
int foo (struct S2 *ptr) { return ptr->b.a; }
-----------------------------------------------------------

b and c are both 16-bit fields, but ptr->b.a uses a 32-bit access.
It therefore loads volatile field c despite c not being in the
same bitfield group as b.a:

foo:
        ldr     w0, [x0]
        sxth    w0, w0
        ret

The problem seems to be that get_inner_reference commits too
early to using the mode of the bitfield's underlying type,
and we rely on:

  /* The memory must be sufficiently aligned for a MODESIZE access.
     This condition guarantees, that the memory access will not
     touch anything after the end of the structure.  */
  if (MEM_ALIGN (op0) < modesize)
    return false;

from strict_volatile_bitfield_p to roll back incorrect decisions.
But in this case, the layout of S2 guarantees 4-byte alignment,
so the opt-out doesn't work.

I was originally looking at the simpler:

-----------------------------------------------------------
struct S1 { volatile int a : 16; } __attribute__((packed));
struct S1 s;
int foo () { return s.a; }
-----------------------------------------------------------

which also exhibits the problem, but I guess it could be
argued in that case that the extra 2 bytes are guaranteed
to be dead space.

See also the testcase for PR69990.