BPF List
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: Alexei Starovoitov <alexei.starovoitov@gmail.com>,
	bot+bpf-ci@kernel.org,  bpf <bpf@vger.kernel.org>,
	Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	 Kernel Team <kernel-team@fb.com>,
	Yonghong Song <yonghong.song@linux.dev>,
	Martin KaFai Lau	 <martin.lau@kernel.org>,
	Chris Mason <mason@kernel.org>,
	Ihor Solodrai	 <ihor.solodrai@linux.dev>
Subject: Re: [PATCH bpf-next 02/11] bpf: do not intersect with current register range on clamp
Date: Mon, 26 Oct 2026 11:32:20 -0700	[thread overview]
Message-ID: <dc27fabc3f3c7d862c3f2ae583a3650a4d48804d.camel@gmail.com> (raw)
In-Reply-To: <CAADnVQLgRWzEnAPJQ7FWZOYWEqYeGaWqQXEvitNaVw8w6oq_3w@mail.gmail.com>

On Sat, 2026-10-24 at 22:10 -0700, Alexei Starovoitov wrote:
> On Sat, Oct 24, 2026 at 6:03 PM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Sat Oct 24, 2026 at 6:57 AM UTC, Eduard Zingerman wrote:
> > > On Sat, 2026-10-24 at 00:41 +0000, bot+bpf-ci@kernel.org wrote:
> > >
> > > ...
> > >
> > > > Since bisection can land on this commit, could that change be folded into
> > > > this patch or ordered before it?
> > >
> > > Commits should remain separate for documentation purposes.
> > > Full test suite passes on both.
> > >
> > > > A related question about the end of the series.  cf18840bc068 only helps
> > > > when the current frame has no active loop.  Consider states inside an inner
> > > > loop that is entered again on the second iteration of a terminating outer
> > > > loop.  current_loop() finds the inner loop in both states, but its
> > > > entry_state differs, because handle_loop_entry_exit() splits a new one on
> > > > each entry.  So the EXACT check runs, and loop_stack_safe() does not
> > > > compare entry_state.
> > > >
> > > > With the outer induction variable now the same on every outer iteration, a
> > > > program like the one below looks like it would still hit "infinite loop
> > > > detected" after cf18840bc068 (with the old code the outer induction
> > > > variable was [1..9] on the second outer iteration and the EXACT compare
> > > > failed):
> > > >
> > > >     w1 = 1;
> > > >     *(u32 *)(r10 - 8) = r1;
> > > >     r6 = 0;
> > > > 1:  r7 = 0;
> > > > 2:  *(u32 *)(r10 - 4) = 1;   /* fp-8 spill -> STACK_MISC */
> > > >     r7 += 1;
> > > >     if r7 < 3 goto 2b;
> > > >     r6 += 1;
> > > >     if r6 < 10 goto 1b;
> > > >     r0 = *(u32 *)(r10 - 8);
> > > >     exit;
> > > >
> > > > Is that case covered somewhere I missed?
> > >
> > > This example is valid. Need to relax the condition in the
> > > current_loop() or bpf_is_state_visited().
> >
> > so you're going to respin it or follow up?
> >
> > It's fine to ignore CI in patch 3.
> > We'll be removing states.c soon.
>
> respin. The better fix is probably:
> -               bounds.r64 = cnum64_intersect(reg->r64, bounds.r64);
> -               bounds.r32 = cnum32_intersect(reg->r32, bounds.r32);
> -               if (cnum64_is_empty(bounds.r64)) {
> -                       verifier_bug(env, "scev clamp produced empty
> range for r%d", r);
> -                       return -EFAULT;
> +               r64 = cnum64_intersect(reg->r64, bounds.r64);
> +               r32 = cnum32_intersect(reg->r32, bounds.r32);
> +               /*
> +                * The state at the head doesn't know how the
> variables depend on each other.
> +                * It lets r6 = 0, r7 = 9 into the loop when both
> count from 0, and r7 = 10
> +                * comes back. No run gets here like that, so any
> range is right for r7.
> +                * Take the one it has at the head: the rest of the
> state is still compared
> +                * with the head, and what was pruned on the way here
> relies on that.
> +                */
> +               if (!cnum64_is_empty(r64) && !cnum32_is_empty(r32)) {
> +                       bounds.r64 = r64;
> +                       bounds.r32 = r32;

Well, it's a minimal change, but I think it is still prone to
counter-examples. I'd still like to remove the clamping logic
altogether and adjust the bpf_is_state_visited() as follows:

--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -1532,10 +1532,10 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
                         */
                        old_loop = current_loop(&sl->state);
                        cur_loop = current_loop(cur);
-                       if (old_loop && cur_loop &&
-                           old_loop->terminates && cur_loop->terminates &&
-                           old_loop->entry_state == cur_loop->entry_state) {
-                               if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) {
+                       if (old_loop && cur_loop) {
+                               if (old_loop->terminates && cur_loop->terminates &&
+                                   old_loop->entry_state == cur_loop->entry_state &&
+                                   states_equal(env, &sl->state, cur, RANGE_WITHIN)) {
                                        loop = true;
                                        goto hit;
                                }

Because of the `goto skip_inf_loop_check` check immediately after that
it would avoid the whole set of such problems. (And will be in the
same line as iterators).

An alternative, if we want to preserve clamping (but I see no reason to),
would be an additional check in check_cond_jmp_op(),
when jump prediction is done. There, for a latch condition,
a call to scev.c can be made, checking if induction variables would
have an empty range.

  reply	other threads:[~2026-10-26 18:32 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24  0:03 [PATCH bpf-next 00/11] bpf: fixes and follow-ups for 32-/64-bit scalar evolution Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 01/11] bpf: reject pointer operands for 32-bit recurrences/latches Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 02/11] bpf: do not intersect with current register range on clamp Eduard Zingerman
2026-10-24  0:41   ` bot+bpf-ci
2026-10-24  6:57     ` Eduard Zingerman
2026-10-25  1:03       ` Alexei Starovoitov
2026-10-25  5:10         ` Alexei Starovoitov
2026-10-26 18:32           ` Eduard Zingerman [this message]
2026-10-24  0:03 ` [PATCH bpf-next 03/11] bpf: look for current loop in upper frames in states_equal() Eduard Zingerman
2026-10-24  0:27   ` sashiko-bot
2026-10-24  0:41   ` bot+bpf-ci
2026-10-24  0:03 ` [PATCH bpf-next 04/11] bpf: check the iteration count before the predicted exit value Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 05/11] bpf: (zext32 (zext32 X)) -> (zext32 X) SCEV simplification rule Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 06/11] bpf: print 32-bit SCEV bounds as 32-bit numbers Eduard Zingerman
2026-10-24  0:41   ` bot+bpf-ci
2026-10-24  0:03 ` [PATCH bpf-next 07/11] selftests/bpf: pointer operands for 32-bit recurrences/latches Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 08/11] selftests/bpf: cases with empty range error under old clamping logic Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 09/11] selftests/bpf: case reporting infinite loop w/o current_loop() changes Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 10/11] selftests/bpf: 32-bit copy of the counter compared at the latch Eduard Zingerman
2026-10-24  0:03 ` [PATCH bpf-next 11/11] selftests/bpf: Restore stack pointer subrange pruning coverage Eduard Zingerman
2026-10-24  5:11 ` [PATCH bpf-next 00/11] bpf: fixes and follow-ups for 32-/64-bit scalar evolution Alexei Starovoitov
2026-10-24  5:33   ` Eduard Zingerman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dc27fabc3f3c7d862c3f2ae583a3650a4d48804d.camel@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bot+bpf-ci@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=ihor.solodrai@linux.dev \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@kernel.org \
    --cc=mason@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox