On 9/4/25 7:53 PM, Hoyeon Lee wrote:
Add a compile-time check to bpf_tail_call_static() to warn when a constant slot(index) is >= map->max_entries. This uses a small BPF_MAP_ENTRIES() macro together with Clang's diagnose_if attribute. Clang front-end keeps the map type with a '(*max_entries)[N]' field, so the expression sizeof(*(m)->max_entries) / sizeof(**(m)->max_entries) is resolved to N entirely at compile time. This allows diagnose_if() to emit a warning when a constant slot index is out of range. Out-of-bounds tail call checkup is no-ops at runtime. Emitting a compile-time warning can help developers detect mistakes earlier. The check is currently limited to Clang (due to diagnose_if) and constant indices, but should catch common errors. Signed-off-by: Hoyeon Lee <hoyeon.lee@xxxxxxxx> --- tools/lib/bpf/bpf_helpers.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 80c028540656..0d9551bb90c0 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -173,6 +173,26 @@ bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot) : "r0", "r1", "r2", "r3", "r4", "r5"); } + +#if __has_attribute(diagnose_if) +static __always_inline void __bpf_tail_call_warn(int oob) + __attribute__((diagnose_if(oob, "bpf_tail_call: slot >= max_entries", "warning"))); + +#define BPF_MAP_ENTRIES(m) \ + ((__u32)(sizeof(*(m)->max_entries) / sizeof(**(m)->max_entries))) + +#ifndef bpf_tail_call_static +#define bpf_tail_call_static(ctx, map, slot) \ +({ \ + /* wrapped to avoid double evaluation. */ \ + const __u32 __slot = (slot); \ + __bpf_tail_call_warn(__slot >= BPF_MAP_ENTRIES(map)); \ + /* Avoid re-expand & invoke original as (bpf_tail_call_static)(..) */ \ + (bpf_tail_call_static)(ctx, map, __slot); \ +}) +#endif /* bpf_tail_call_static */ +#endif + #endif #endif
I got compilation failures with llvm21. In file included from progs/bpf_flow.c:19: /home/yhs/work/bpf-next/tools/testing/selftests/bpf/tools/include/bpf/bpf_helpers.h:178:29: error: function '__bpf_tail_call_warn' has internal linkage but is not defined [-Werror,-Wundefined-internal] 178 | static __always_inline void __bpf_tail_call_warn(int oob) | CLNG-BPF [test_progs] btf_type_tag_percpu.bpf.o ^ progs/bpf_flow.c:122:3: note: used here 122 | bpf_tail_call_static(skb, &jmp_table, IP); | ^ /home/yhs/work/bpf-next/tools/testing/selftests/bpf/tools/include/bpf/bpf_helpers.h:189:2: note: expanded from macro 'bpf_tail_call_static' 189 | __bpf_tail_c CLNG-BPF [test_progs] btf_type_tag_user.bpf.o all_warn(__slot >= BPF_MAP_ENTRIES(map)); CLNG-BPF [test_progs] cb_refs.bpf.o \ | ^
-- 2.51.0