[Bug middle-end/105805] New: -fstrict-volatile-bitfields can read beyond the end of the bitfield

rsandifo at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Wed Jun 1 16:28:42 GMT 2022


            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.


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:

        ldr     w0, [x0]
        sxth    w0, w0

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.

More information about the Gcc-bugs mailing list