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 -- 2.51.0