From: Eduard Zateev <hackerowskiy@gmail.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
eddyz87@gmail.com, memxor@gmail.com, martin.lau@linux.dev,
song@kernel.org, yonghong.song@linux.dev, jolsa@kernel.org,
emil@etsalapatis.com, ihor.solodrai@linux.dev,
linux-kernel@vger.kernel.org,
Eduard Zateev <hackerowskiy@gmail.com>
Subject: [PATCH] libbpf: fix helper macro C++ compatibility
Date: Sat, 24 Oct 2026 05:59:02 +0200 [thread overview]
Message-ID: <20261024035902.44566-1-hackerowskiy@gmail.com> (raw)
C++26 warns about the GNU named variadic parameter syntax in
bpf_helpers.h, which prevents consumers from using the header with
-Werror=variadic-macros. Replace the named parameters with __VA_ARGS__.
C++ also rejects implicit conversions used by helper argument packing,
bpf_for_each, and generated helper function pointers. Use explicit
integer and typed pointer casts so these helpers can be parsed and used
from C++.
Verified with GCC and Clang C++26 syntax checks using helper macros,
an ARM64-targeted BPF C smoke build, and generated helper definitions
from scripts/bpf_doc.py. checkpatch.pl reports no errors or warnings.
AI assistance: OpenAI Codex helped reproduce the C++26 failures and
draft changes to tools/lib/bpf/bpf_helpers.h and scripts/bpf_doc.py.
The human submitter must review the changes and test results before
submission.
Fixes: d6a6a55518c1 ("libbpf: Move BPF_SEQ_PRINTF and BPF_SNPRINTF to bpf_helpers.h")
Closes: https://github.com/libbpf/libbpf/issues/974
Signed-off-by: Eduard Zateev <hackerowskiy@gmail.com>
---
scripts/bpf_doc.py | 10 +++-
tools/lib/bpf/bpf_helpers.h | 107 ++++++++++++++++++++++--------------
2 files changed, 72 insertions(+), 45 deletions(-)
diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
index 15d113a1b..02e31ad50 100755
--- a/scripts/bpf_doc.py
+++ b/scripts/bpf_doc.py
@@ -829,6 +829,11 @@ class PrinterHelpersHeader(Printer):
/* Forward declarations of BPF structs */'''
print(header)
+ print("#ifdef __cplusplus")
+ print("#define ___bpf_helper_stub(id, name) reinterpret_cast<decltype(+name)>(id)")
+ print("#else")
+ print("#define ___bpf_helper_stub(id, name) ((void *)(id))")
+ print("#endif")
for fwd in self.type_fwds:
print('%s;' % fwd)
print('')
@@ -849,8 +854,7 @@ class PrinterHelpersHeader(Printer):
print('')
def print_footer(self):
- footer = ''
- print(footer)
+ print("#undef ___bpf_helper_stub")
def map_type(self, t):
if t in self.known_types:
@@ -908,7 +912,7 @@ class PrinterHelpersHeader(Printer):
comma = ', '
print(one_arg, end='')
- print(') = (void *) %d;' % helper.enum_val)
+ print(') = ___bpf_helper_stub(%d, %s);' % (helper.enum_val, proto['name']))
print('')
diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h
index b37b727ef..6c9fdb696 100644
--- a/tools/lib/bpf/bpf_helpers.h
+++ b/tools/lib/bpf/bpf_helpers.h
@@ -233,20 +233,53 @@ enum libbpf_tristate {
#endif
#define ___bpf_fill0(arr, p, x) do {} while (0)
-#define ___bpf_fill1(arr, p, x) arr[p] = x
-#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)
-#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)
-#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)
-#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)
-#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)
-#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)
-#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)
-#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)
-#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)
-#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)
-#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)
-#define ___bpf_fill(arr, args...) \
- ___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)
+#define ___bpf_fill1(arr, p, x) (arr[p] = (unsigned long long)(x))
+#define ___bpf_fill2(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill1(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill3(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill2(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill4(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill3(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill5(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill4(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill6(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill5(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill7(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill6(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill8(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill7(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill9(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill8(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill10(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill9(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill11(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill10(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill12(arr, p, x, ...) do { \
+ arr[p] = (unsigned long long)(x); \
+ ___bpf_fill11(arr, p + 1, __VA_ARGS__); \
+} while (0)
+#define ___bpf_fill(arr, ...) \
+ ___bpf_apply(___bpf_fill, ___bpf_narg(__VA_ARGS__))(arr, 0, __VA_ARGS__)
/*
* Format strings are in a section of their own. When global data of the object
@@ -260,15 +293,12 @@ enum libbpf_tristate {
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
* in a structure.
*/
-#define BPF_SEQ_PRINTF(seq, fmt, args...) \
+#define BPF_SEQ_PRINTF(seq, fmt, ...) \
({ \
static const char ___fmt[] ___bpf_fmt_sec = fmt; \
- unsigned long long ___param[___bpf_narg(args)]; \
+ unsigned long long ___param[___bpf_narg(__VA_ARGS__)]; \
\
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
- ___bpf_fill(___param, args); \
- _Pragma("GCC diagnostic pop") \
+ ___bpf_fill(___param, __VA_ARGS__); \
\
bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
@@ -278,15 +308,12 @@ enum libbpf_tristate {
* BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
* an array of u64.
*/
-#define BPF_SNPRINTF(out, out_size, fmt, args...) \
+#define BPF_SNPRINTF(out, out_size, fmt, ...) \
({ \
static const char ___fmt[] ___bpf_fmt_sec = fmt; \
- unsigned long long ___param[___bpf_narg(args)]; \
+ unsigned long long ___param[___bpf_narg(__VA_ARGS__)]; \
\
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
- ___bpf_fill(___param, args); \
- _Pragma("GCC diagnostic pop") \
+ ___bpf_fill(___param, __VA_ARGS__); \
\
bpf_snprintf(out, out_size, ___fmt, \
___param, sizeof(___param)); \
@@ -309,29 +336,23 @@ enum libbpf_tristate {
* __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
* instead of an array of u64.
*/
-#define __bpf_vprintk(fmt, args...) \
+#define __bpf_vprintk(fmt, ...) \
({ \
static const char ___fmt[] ___bpf_fmt_sec = fmt; \
- unsigned long long ___param[___bpf_narg(args)]; \
+ unsigned long long ___param[___bpf_narg(__VA_ARGS__)]; \
\
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
- ___bpf_fill(___param, args); \
- _Pragma("GCC diagnostic pop") \
+ ___bpf_fill(___param, __VA_ARGS__); \
\
bpf_trace_vprintk(___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
})
-#define bpf_stream_printk(stream_id, fmt, args...) \
+#define bpf_stream_printk(stream_id, fmt, ...) \
({ \
static const char ___fmt[] ___bpf_fmt_sec = fmt; \
- unsigned long long ___param[___bpf_narg(args)]; \
+ unsigned long long ___param[___bpf_narg(__VA_ARGS__)]; \
\
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
- ___bpf_fill(___param, args); \
- _Pragma("GCC diagnostic pop") \
+ ___bpf_fill(___param, __VA_ARGS__); \
\
bpf_stream_vprintk(stream_id, ___fmt, ___param, sizeof(___param)); \
})
@@ -346,7 +367,7 @@ enum libbpf_tristate {
__bpf_printk /*1*/, __bpf_printk /*0*/)
/* Helper macro to print out debug messages */
-#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
+#define bpf_printk(fmt, ...) ___bpf_pick_printk(__VA_ARGS__)(fmt, ##__VA_ARGS__)
struct bpf_iter_num;
@@ -382,16 +403,18 @@ extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
* extension: __attribute__((cleanup(<func>))), supported by both GCC and
* Clang.
*/
-#define bpf_for_each(type, cur, args...) for ( \
+#define bpf_for_each(type, cur, ...) for ( \
/* initialize and define destructor */ \
struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */, \
cleanup(bpf_iter_##type##_destroy))), \
/* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */ \
*___p __attribute__((unused)) = ( \
- bpf_iter_##type##_new(&___it, ##args), \
+ bpf_iter_##type##_new(&___it, \
+ ##__VA_ARGS__), \
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
/* for bpf_iter_##type##_destroy() when used from cleanup() attribute */ \
- (void)bpf_iter_##type##_destroy, (void *)0); \
+ (void)bpf_iter_##type##_destroy, \
+ (struct bpf_iter_##type *)0); \
/* iteration and termination check */ \
(((cur) = bpf_iter_##type##_next(&___it))); \
)
--
2.55.0
next reply other threads:[~2026-10-24 3:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 3:59 Eduard Zateev [this message]
2026-10-24 4:24 ` [PATCH] libbpf: fix helper macro C++ compatibility sashiko-bot
2026-10-24 4:36 ` bot+bpf-ci
2026-10-24 19:16 ` Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261024035902.44566-1-hackerowskiy@gmail.com \
--to=hackerowskiy@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.