Add a compile-time check to bpf_tail_call_static() to warn when a constant slot(index) >= 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 calls are currently silent no-ops at runtime, so emitting a compile-time warning helps detect logic errors earlier. This is currently limited to Clang (due to diagnose_if) and only for constant indices, but should still catch the common cases. Signed-off-by: Hoyeon Lee <hoyeon.lee@xxxxxxxx> --- Changes in V2: - add function definition for __bpf_tail_call_warn for compile error tools/lib/bpf/bpf_helpers.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 80c028540656..98bc1536c497 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -173,6 +173,27 @@ 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