All of lore.kernel.org
 help / color / mirror / Atom feed
* LLVM regression in memcpy struct bpf_sock_ops->remote_ip6 to struct in6_addr
@ 2026-07-21 23:56 YiFei Zhu
  2026-08-19  6:01 ` Yonghong Song
  0 siblings, 1 reply; 2+ messages in thread
From: YiFei Zhu @ 2026-07-21 23:56 UTC (permalink / raw)
  To: bpf, Ömer Sinan Ağacan, yonghong-song

In one of our BPF progs, there is a pattern of copying IPv6 addresses
(which are four u32s) off of struct bpf_sock_ops into a stack variable
(a larger struct that contains struct in6_addr), then updating a map
with that stack variable. After a recent LLVM upgrade, that program no
longer loads.

I wrote a reproducer:

  #include <string.h>
  #include <linux/in6.h>
  #include <linux/bpf.h>
  #include <bpf/bpf_helpers.h>

  struct in6_addr addr6;

  SEC("sockops")
  int test(struct bpf_sock_ops *skops)
  {
          struct in6_addr stack_addr6;

          memcpy(&stack_addr6, skops->remote_ip6, sizeof(skops->remote_ip6));
          addr6 = stack_addr6;
          return 0;
  }

This will fail loading at latest LLVM main with error:

  -- BEGIN PROG LOAD LOG --
  0: R1=ctx() R10=fp0
  0: (7b) *(u64 *)(r10 -8) = r1         ; R1=ctx() R10=fp0 fp-8=ctx()
  1: (79) r1 = *(u64 *)(r10 -8)         ; R1=ctx() R10=fp0 fp-8=ctx()
  2: (79) r2 = *(u64 *)(r1 +40)
  invalid bpf_context access off=40 size=8
  processed 3 insns (limit 1000000) max_states_per_insn 0 total_states
0 peak_states 0 mark_read 0
  -- END PROG LOAD LOG --

It seems that the program is reading the address from the bpf_sock_ops
as two u64s instead of four u32s, and the verifier understandably does
not allow that due to the complexity of rewriting context accesses. I
bisected the regression to

  commit 790f0623411d5d9d5c989f14e87f2fe86f52eaf3
  Author: Ömer Sinan Ağacan <omeragacan@gmail.com>
  Date:   Tue Jun 9 16:03:26 2026

      [SelectionDAG] Pass dest and src alignments separately to memcpy
and memmove lowering functions (#201119)

Looking at its PR [1], it seems that commit caused another regression
for BPF selftests and that has been fixed, but this regression is
still reproducible on main with that fix applied.

I'm not really familiar enough with LLVM internals to understand
exactly why it generates the code this way or how to fix the
regression.

YiFei Zhu

[1] https://github.com/llvm/llvm-project/pull/201119

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: LLVM regression in memcpy struct bpf_sock_ops->remote_ip6 to struct in6_addr
  2026-07-21 23:56 LLVM regression in memcpy struct bpf_sock_ops->remote_ip6 to struct in6_addr YiFei Zhu
@ 2026-08-19  6:01 ` Yonghong Song
  0 siblings, 0 replies; 2+ messages in thread
From: Yonghong Song @ 2026-08-19  6:01 UTC (permalink / raw)
  To: YiFei Zhu, bpf, Ömer Sinan Ağacan, yonghong-song



On 7/21/26 4:56 PM, YiFei Zhu wrote:
> In one of our BPF progs, there is a pattern of copying IPv6 addresses
> (which are four u32s) off of struct bpf_sock_ops into a stack variable
> (a larger struct that contains struct in6_addr), then updating a map
> with that stack variable. After a recent LLVM upgrade, that program no
> longer loads.
>
> I wrote a reproducer:
>
>    #include <string.h>
>    #include <linux/in6.h>
>    #include <linux/bpf.h>
>    #include <bpf/bpf_helpers.h>
>
>    struct in6_addr addr6;
>
>    SEC("sockops")
>    int test(struct bpf_sock_ops *skops)
>    {
>            struct in6_addr stack_addr6;
>
>            memcpy(&stack_addr6, skops->remote_ip6, sizeof(skops->remote_ip6));
>            addr6 = stack_addr6;
>            return 0;
>    }
>
> This will fail loading at latest LLVM main with error:
>
>    -- BEGIN PROG LOAD LOG --
>    0: R1=ctx() R10=fp0
>    0: (7b) *(u64 *)(r10 -8) = r1         ; R1=ctx() R10=fp0 fp-8=ctx()
>    1: (79) r1 = *(u64 *)(r10 -8)         ; R1=ctx() R10=fp0 fp-8=ctx()
>    2: (79) r2 = *(u64 *)(r1 +40)
>    invalid bpf_context access off=40 size=8
>    processed 3 insns (limit 1000000) max_states_per_insn 0 total_states
> 0 peak_states 0 mark_read 0
>    -- END PROG LOAD LOG --

Are you using -O0 compile flag? The above code is not optimal.

I tried with llvm23/-O2, cpu v3, and get the following code:

        0:       w2 = *(u32 *)(r1 + 0x2c)
        1:       r3 = 0x0 ll
                 0000000000000008:  R_BPF_64_64  addr6
        3:       *(u32 *)(r3 + 0xc) = w2
        4:       w2 = *(u32 *)(r1 + 0x28)
        5:       *(u32 *)(r3 + 0x8) = w2
        6:       w2 = *(u32 *)(r1 + 0x24)
        7:       *(u32 *)(r3 + 0x4) = w2
        8:       w1 = *(u32 *)(r1 + 0x20)
        9:       *(u32 *)(r3 + 0x0) = w1
       10:       w0 = 0x0
       11:       exit

>
> It seems that the program is reading the address from the bpf_sock_ops
> as two u64s instead of four u32s, and the verifier understandably does
> not allow that due to the complexity of rewriting context accesses. I
> bisected the regression to
>
>    commit 790f0623411d5d9d5c989f14e87f2fe86f52eaf3
>    Author: Ömer Sinan Ağacan <omeragacan@gmail.com>
>    Date:   Tue Jun 9 16:03:26 2026
>
>        [SelectionDAG] Pass dest and src alignments separately to memcpy
> and memmove lowering functions (#201119)
>
> Looking at its PR [1], it seems that commit caused another regression
> for BPF selftests and that has been fixed, but this regression is
> still reproducible on main with that fix applied.
>
> I'm not really familiar enough with LLVM internals to understand
> exactly why it generates the code this way or how to fix the
> regression.
>
> YiFei Zhu
>
> [1] https://github.com/llvm/llvm-project/pull/201119
>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-19  6:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 23:56 LLVM regression in memcpy struct bpf_sock_ops->remote_ip6 to struct in6_addr YiFei Zhu
2026-08-19  6:01 ` Yonghong Song

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.