Re: [PATCH bpf-next v4 1/6] bpf: Correct the overflow check comment in bpf_iter_num_next()

Andrii Nakryiko <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <CAEf4BzYvGPYa6CdoPwMFGq3L+cdQT7FJu6si8icP==fc_6797w@mail.gmail.com>
On Wed, Jul 29, 2026 at 1:36 PM Puranjay Mohan <[email protected]> wrote:
>
> bpf_iter_num_next() decides whether the iterator is exhausted with:
>
>         if ((s64)(s->cur + 1) >= s->end) {
>
> The comment above it claimed the (s64) cast was needed to be careful
> about overflow, "e.g., if s->cur == s->end == INT_MAX, we can't just do
> s->cur + 1 >= s->end". That reasoning is wrong: s->cur + 1 is evaluated
> in int and wraps *before* the cast, so casting the already-wrapped result
> to s64 changes nothing. For s->cur == s->end == INT_MAX the plain
> s->cur + 1 >= s->end and the (s64) version both evaluate to false, and
> more generally the two are identical for all inputs (sign-extending both
> operands of a signed compare never changes its result).
>
> The wraparound of s->cur + 1 is in fact intentional and load-bearing:
> bpf_iter_num_new() initializes s->cur to start - 1, which wraps to
> INT_MAX when start == INT_MIN, and the wrapping s->cur + 1 recovers
> start on the first call. Using real 64-bit arithmetic ((s64)s->cur + 1)
> would instead break iterators starting at INT_MIN.
>
> Drop the redundant cast and rewrite the comment to describe what actually
> happens. No functional change; the kernel builds with -fno-strict-overflow
> so the signed wraparound is well defined.
>
> Signed-off-by: Puranjay Mohan <[email protected]>
> ---
>  kernel/bpf/bpf_iter.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
> index f5eaeb2493d4a..f190f2b250048 100644
> --- a/kernel/bpf/bpf_iter.c
> +++ b/kernel/bpf/bpf_iter.c
> @@ -802,12 +802,14 @@ __bpf_kfunc int *bpf_iter_num_next(struct bpf_iter_num* it)
>  {
>         struct bpf_iter_num_kern *s = (void *)it;
>
> -       /* check failed initialization or if we are done (same behavior);
> -        * need to be careful about overflow, so convert to s64 for checks,
> -        * e.g., if s->cur == s->end == INT_MAX, we can't just do
> -        * s->cur + 1 >= s->end
> +       /* Detect the end of the range, or a failed/empty iterator: all of these
> +        * leave s->cur + 1 >= s->end. bpf_iter_num_new() set s->cur to start - 1
> +        * (which wraps to INT_MAX when start == INT_MIN), so the s->cur + 1 below
> +        * is a deliberate 32-bit wraparound that recovers start. As s->cur and
> +        * s->end are int, this is an ordinary signed 32-bit compare, exactly what
> +        * the inlined bpf_iter_num_next() emits.
>          */

this is really Claude-style verboseness. let's just say that num iter
maintains an invariant that either s->cur < s->end or s->cur == s->end
== 0, in both cases s->cur + 1 can't overflow int.


> -       if ((s64)(s->cur + 1) >= s->end) {
> +       if (s->cur + 1 >= s->end) {
>                 s->cur = s->end = 0;
>                 return NULL;
>         }
> --
> 2.53.0-Meta
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.