From 14aadb945dffb657dd9bfd8755de831419c71dd9 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 27 Aug 2025 21:46:45 +0200 Subject: [PATCH 1/2] selftests/bpf: Annotate bpf_obj_new_impl() with __must_check The verifier requires that pointers returned by bpf_obj_new_impl() are either dropped or stored in a map. Therefore programs that do not use its return values will fail to load. Make the compiler point out these issues. Adjust selftests that check that the verifier does indeed spot these bugs. Note that now there two different bpf_obj_new_impl() declarations: one with __must_check from bpf_experimental.h, and one without from vmlinux.h. According to the GCC doc [1] this is fine and has the desired effect: Compatible attribute specifications on distinct declarations of the same function are merged. [1] https://gcc.gnu.org/onlinedocs/gcc-12.4.0/gcc/Function-Attributes.html Link: https://lore.kernel.org/bpf/CAADnVQL6Q+QRv3_JwEd26biwGpFYcwD_=BjBJWLAtpgOP9CKRw@mail.gmail.com/ Suggested-by: Alexei Starovoitov Signed-off-by: Ilya Leoshkevich --- .../testing/selftests/bpf/bpf_experimental.h | 6 ++++- .../selftests/bpf/progs/linked_list_fail.c | 23 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h index da7e230f2781e..a8f206f4fdb9c 100644 --- a/tools/testing/selftests/bpf/bpf_experimental.h +++ b/tools/testing/selftests/bpf/bpf_experimental.h @@ -8,6 +8,10 @@ #define __contains(name, node) __attribute__((btf_decl_tag("contains:" #name ":" #node))) +#ifndef __must_check +#define __must_check __attribute__((__warn_unused_result__)) +#endif + /* Description * Allocates an object of the type represented by 'local_type_id' in * program BTF. User may use the bpf_core_type_id_local macro to pass the @@ -20,7 +24,7 @@ * A pointer to an object of the type corresponding to the passed in * 'local_type_id', or NULL on failure. */ -extern void *bpf_obj_new_impl(__u64 local_type_id, void *meta) __ksym; +extern __must_check void *bpf_obj_new_impl(__u64 local_type_id, void *meta) __ksym; /* Convenience macro to wrap over bpf_obj_new_impl */ #define bpf_obj_new(type) ((type *)bpf_obj_new_impl(bpf_core_type_id_local(type), NULL)) diff --git a/tools/testing/selftests/bpf/progs/linked_list_fail.c b/tools/testing/selftests/bpf/progs/linked_list_fail.c index 6438982b928bd..1e30d103e1c72 100644 --- a/tools/testing/selftests/bpf/progs/linked_list_fail.c +++ b/tools/testing/selftests/bpf/progs/linked_list_fail.c @@ -212,22 +212,33 @@ int map_compat_raw_tp_w(void *ctx) SEC("?tc") int obj_type_id_oor(void *ctx) { - bpf_obj_new_impl(~0UL, NULL); + void *f; + + f = bpf_obj_new_impl(~0UL, NULL); + (void)f; + return 0; } SEC("?tc") int obj_new_no_composite(void *ctx) { - bpf_obj_new_impl(bpf_core_type_id_local(int), (void *)42); + void *f; + + f = bpf_obj_new_impl(bpf_core_type_id_local(int), (void *)42); + (void)f; + return 0; } SEC("?tc") int obj_new_no_struct(void *ctx) { + void *f; + + f = bpf_obj_new(union { int data; unsigned udata; }); + (void)f; - bpf_obj_new(union { int data; unsigned udata; }); return 0; } @@ -252,7 +263,11 @@ int new_null_ret(void *ctx) SEC("?tc") int obj_new_acq(void *ctx) { - bpf_obj_new(struct foo); + void *f; + + f = bpf_obj_new(struct foo); + (void)f; + return 0; } From 3319169c58d6b049f7ecd4a5ff3b7f4a765dfdb6 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 27 Aug 2025 21:46:46 +0200 Subject: [PATCH 2/2] selftests/bpf: Fix "expression result unused" warnings with icecc icecc is a compiler wrapper that distributes compile jobs over a build farm [1]. It works by sending toolchain binaries and preprocessed source code to remote machines. Unfortunately using it with BPF selftests causes build failures due to a clang bug [2]. The problem is that clang suppresses the -Wunused-value warning if the unused expression comes from a macro expansion. Since icecc compiles preprocessed source code, this information is not available. This leads to -Wunused-value false positives. arena_spin_lock_slowpath() uses two macros that produce values and ignores the results. Add (void) cast to explicitly indicate that this is intentional and suppress the warning. An alternative solution is to change the macros to not produce values. This would work today, but in the future there may appear users who need them. Another potential solution is to replace these macros with functions. Unfortunately this would not work, because these macros work with unknown types and control flow. [1] https://github.com/icecc/icecream [2] https://github.com/llvm/llvm-project/issues/142614 Signed-off-by: Ilya Leoshkevich --- tools/testing/selftests/bpf/progs/bpf_arena_spin_lock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/bpf_arena_spin_lock.h b/tools/testing/selftests/bpf/progs/bpf_arena_spin_lock.h index d67466c1ff775..f90531cf3ee59 100644 --- a/tools/testing/selftests/bpf/progs/bpf_arena_spin_lock.h +++ b/tools/testing/selftests/bpf/progs/bpf_arena_spin_lock.h @@ -302,7 +302,7 @@ int arena_spin_lock_slowpath(arena_spinlock_t __arena __arg_arena *lock, u32 val * barriers. */ if (val & _Q_LOCKED_MASK) - smp_cond_load_acquire_label(&lock->locked, !VAL, release_err); + (void)smp_cond_load_acquire_label(&lock->locked, !VAL, release_err); /* * take ownership and clear the pending bit. @@ -380,7 +380,7 @@ int arena_spin_lock_slowpath(arena_spinlock_t __arena __arg_arena *lock, u32 val /* Link @node into the waitqueue. */ WRITE_ONCE(prev->next, node); - arch_mcs_spin_lock_contended_label(&node->locked, release_node_err); + (void)arch_mcs_spin_lock_contended_label(&node->locked, release_node_err); /* * While waiting for the MCS lock, the next pointer may have