On Tue, 2024-05-28 at 20:22 -0700, Alexei Starovoitov wrote: [...] > > > However, below is an example where if comparison is BPF_X. > > Note that I obfuscated constant 5 as a volatile variable. > > And here is what happens when verifier rejects the program: > > Sounds pretty much like: doctor it hurts when I do that. Well, the point is not in the volatile variable but in the BPF_X comparison instruction. The bound might a size of some buffer, e.g. encoded like this: struct foo { int *items; int max_items; // suppose this is 5 for some verification path }; // and 7 for another. And you don't need bpf_for specifically, an outer loop with can_loop should also lead to get_loop_entry(...) being non-NULL. > > + volatile unsigned long five = 5; > > + unsigned long sum = 0, i = 0; > > + struct bpf_iter_num it; > > + int *v; > > + > > + bpf_iter_num_new(&it, 0, 10); > > + while ((v = bpf_iter_num_next(&it))) { > > + if (i < five) > > + sum += arr[i++]; > > If you're saying that the verifier should accept that > no matter what then I have to disagree. > Not interested in avoiding issues in programs that > are actively looking to explore a verifier implementation detail. I don't think that this is a very exotic pattern, such code could be written if one has a buffer with a dynamic bound and seeks to fill it with items from some collection applying filtering. I do not insist that varifier should accept such programs, but since we are going for heuristics to do the widening, I think we should try and figure out a few examples when heuristics breaks, just to understand if that is ok.