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

David Faust <dfaust at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2026-01-14
     Ever confirmed|0                           |1

--- Comment #1 from David Faust <dfaust at gcc dot gnu.org> ---
The problematic bit seems to be:

struct rhash_head {
 struct rhash_head *next;
};

struct flow_offload_tuple {
  ...
  __u8 l3proto;
  __u8 l4proto;
  struct {
    __u16 id;
    __be16 proto;
  } encap[2];

  struct { } __hash;

  __u8 dir:2,             <---- offset 50 #B in struct flow_offload_tuple,
       xmit_type:3,                 =  58 #B in struct flow_offload_tuple_rhash
       encap_num:2,
       in_vlan_ingress:2;
  __u16 mtu;
 ...
};

struct flow_offload_tuple_rhash {
 struct rhash_head node;
 struct flow_offload_tuple tuple;
};

int foo (struct flow_offload_tuple_rhash *tuplehash)
{
  if (tuplehash->tuple.xmit_type != 1)
    return 0;
  if (tuplehash->tuple.dir >= 2)
    return 0;

  return -1;
}

(adapted from lines 5035-5039 of the linked .i)

0000000000000000 <foo>:
   0:   69 10 3a 00 00 00 00 00         ldxh %r0,[%r1+58]
   8:   54 00 00 00 1c 00 00 00         and32 %r0,28
  10:   56 00 08 00 04 00 00 00         jne32 %r0,4,8
  18:   79 11 38 00 00 00 00 00         ldxdw %r1,[%r1+56]    <-- problematic
load
  20:   b7 00 00 00 01 00 00 00         mov %r0,1
  28:   77 01 00 00 10 00 00 00         rsh %r1,16
  30:   54 01 00 00 03 00 00 00         and32 %r1,3
  38:   2e 01 05 00 00 00 00 00         jgt32 %r1,%r0,5
  ...

the ldxdw %r1,[%r1+56] corresponds to the verifier error:
          82: (79) r9 = *(u64 *)(r7 +56)
          access beyond struct (anon) at off 2 size 8

I think the verifier complains because the 8 byte ldxdw
begins inside the preceding encap[2] field and runs off
the end of it to the bitfields.

Clang doesn't generate a second load here, and neither
does gcc for say x86_64, since we can obviously reuse the
prior load to %r0 if we used different registers to mask
the bitfields.

Also, by changing the >= 2 to something else like ==2,
we do not emit the ldxdw and "do the right thing"
by reusing the prior ldxh and using two different regs
to mask xmit_type and dir.

Increasing the cost of loads might improve the code gen
for this case.

But it looks like we probably also need to do something to
prevent generating loads which run off the end of struct fields
to satisfy the verifier.  Probably the complaint is because
this would be an issue if the encap[2] field were a kernel
type that could change size with CO-RE relocation.

Reply via email to