https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105805
Bug ID: 105805 Summary: -fstrict-volatile-bitfields can read beyond the end of the bitfield Product: gcc Version: 12.0 Status: UNCONFIRMED Keywords: wrong-code Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: rsandifo at gcc dot gnu.org Target Milestone: --- 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.