This commit fixes a compilation error on systems with glibc < 2.26 [0]: ``` In file included from main.h:14:0, from gen.c:24: linux/tools/include/tools/libc_compat.h:11:21: error: attempt to use poisoned "reallocarray" static inline void *reallocarray(void *ptr, size_t nmemb, size_t size) ``` This happens because gen.c pulls <bpf/libbpf_internal.h>, and then <tools/libc_compat.h> (through main.h). When COMPAT_NEED_REALLOCARRAY is set, libc_compat.h defines reallocarray() which libbpf_internal.h poisons with a GCC pragma. This follows the same approach of libbpf in commit 029258d7b228 ("libbpf: Remove any use of reallocarray() in libbpf"). Reported-by: Quentin Monnet <quentin@xxxxxxxxxxxxx> Signed-off-by: Mauricio Vásquez <mauricio@xxxxxxxxxx> [0]: https://lore.kernel.org/bpf/3bf2bd49-9f2d-a2df-5536-bc0dde70a83b@xxxxxxxxxxxxx/ --- tools/bpf/bpftool/Makefile | 6 +----- tools/bpf/bpftool/main.h | 34 ++++++++++++++++++++++++++++++- tools/bpf/bpftool/prog.c | 6 +++--- tools/bpf/bpftool/xlated_dumper.c | 4 ++-- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index a137db96bd56..ba647aede0d6 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -93,7 +93,7 @@ INSTALL ?= install RM ?= rm -f FEATURE_USER = .bpftool -FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ +FEATURE_TESTS = libbfd disassembler-four-args zlib libcap \ clang-bpf-co-re FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ clang-bpf-co-re @@ -118,10 +118,6 @@ ifeq ($(feature-disassembler-four-args), 1) CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE endif -ifeq ($(feature-reallocarray), 0) -CFLAGS += -DCOMPAT_NEED_REALLOCARRAY -endif - LIBS = $(LIBBPF) -lelf -lz LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz ifeq ($(feature-libcap), 1) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 0c3840596b5a..6a5775373640 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -8,10 +8,10 @@ #undef GCC_VERSION #include <stdbool.h> #include <stdio.h> +#include <stdlib.h> #include <linux/bpf.h> #include <linux/compiler.h> #include <linux/kernel.h> -#include <tools/libc_compat.h> #include <bpf/hashmap.h> #include <bpf/libbpf.h> @@ -21,6 +21,9 @@ /* Make sure we do not use kernel-only integer typedefs */ #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 +/* prevent accidental re-addition of reallocarray() */ +#pragma GCC poison reallocarray + static inline __u64 ptr_to_u64(const void *ptr) { return (__u64)(unsigned long)ptr; @@ -264,4 +267,33 @@ static inline bool hashmap__empty(struct hashmap *map) return map ? hashmap__size(map) == 0 : true; } +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +/* + * Re-implement glibc's reallocarray() for bpftool internal-only use. + * reallocarray(), unfortunately, is not available in all versions of glibc, + * so requires extra feature detection and using reallocarray() stub from + * <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates + * build of bpftool unnecessarily and is just a maintenance burden. Instead, + * it's trivial to implement bpftool-specific internal version and use it + * throughout bpftool. + * Copied from tools/lib/bpf/libbpf_internal.h + */ +static inline void *bpftool_reallocarray(void *ptr, size_t nmemb, size_t size) +{ + size_t total; + +#if __has_builtin(__builtin_mul_overflow) + if (unlikely(__builtin_mul_overflow(nmemb, size, &total))) + return NULL; +#else + if (size == 0 || nmemb > ULONG_MAX / size) + return NULL; + total = nmemb * size; +#endif + return realloc(ptr, total); +} + #endif diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 92a6f679ef7d..860ad234166c 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -1558,9 +1558,9 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) if (fd < 0) goto err_free_reuse_maps; - new_map_replace = reallocarray(map_replace, - old_map_fds + 1, - sizeof(*map_replace)); + new_map_replace = bpftool_reallocarray(map_replace, + old_map_fds + 1, + sizeof(*map_replace)); if (!new_map_replace) { p_err("mem alloc failed"); goto err_free_reuse_maps; diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c index f1f32e21d5cd..467bce9eee09 100644 --- a/tools/bpf/bpftool/xlated_dumper.c +++ b/tools/bpf/bpftool/xlated_dumper.c @@ -32,8 +32,8 @@ void kernel_syms_load(struct dump_data *dd) return; while (fgets(buff, sizeof(buff), fp)) { - tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1, - sizeof(*dd->sym_mapping)); + tmp = bpftool_reallocarray(dd->sym_mapping, dd->sym_count + 1, + sizeof(*dd->sym_mapping)); if (!tmp) { out: free(dd->sym_mapping); -- 2.25.1