[PATCH v3 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts

WanLi Niu posted 1 patch 1 month ago
There is a newer version of this series
tools/bpf/bpftool/gen.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
[PATCH v3 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by WanLi Niu 1 month ago
From: WanLi Niu <niuwl1@chinatelecom.cn>

Fix C++ compilation errors in generated skeleton by adding explicit
pointer casts and using integer subtraction for offset calculation.

Use struct outer::inner syntax under __cplusplus to access nested skeleton map
structs, ensuring C++ compilation compatibility while preserving C support

error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
      |         skel = skel_alloc(sizeof(*skel));
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~
      |                          |
      |                          void*

error: arithmetic on pointers to void
      |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
      |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                 sizeof(data) - 1);
      |                                                 ~~~~~~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
      |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
changelog:
v3:
- Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song

v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
- Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)

v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
---
 tools/bpf/bpftool/gen.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 993c7d9484a4..010861b7d0ea 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		{							    \n\
 			struct %1$s *skel;				    \n\
 									    \n\
-			skel = skel_alloc(sizeof(*skel));		    \n\
+			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
 			if (!skel)					    \n\
 				goto cleanup;				    \n\
-			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
+			skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\
 		",
 		obj_name, opts.data_sz);
 	bpf_object__for_each_map(map, obj) {
@@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		\n\
 		\";							    \n\
 									    \n\
+		#ifdef __cplusplus                                          \n\
+				skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\
+		#else                                                       \n\
 				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
+		#endif							    \n\
 								sizeof(data) - 1);\n\
 				if (!skel->%1$s)			    \n\
 					goto cleanup;			    \n\
 				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
 			}						    \n\
-			", ident, bpf_map_mmap_sz(map));
+			", ident, bpf_map_mmap_sz(map), obj_name);
 	}
 	codegen("\
 		\n\
@@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 
 		codegen("\
 		\n\
+		#ifdef __cplusplus					    \n\
+			skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
+		#else							    \n\
 			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
+		#endif							    \n\
 							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
 			if (!skel->%1$s)				    \n\
 				return -ENOMEM;				    \n\
 			",
-		       ident, bpf_map_mmap_sz(map), mmap_flags);
+		       ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
 	}
 	codegen("\
 		\n\
-- 
2.39.1
Re: [PATCH v3 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by Andrii Nakryiko 1 month ago
On Sat, Jan 3, 2026 at 6:15 PM WanLi Niu <kiraskyler@163.com> wrote:
>
> From: WanLi Niu <niuwl1@chinatelecom.cn>
>
> Fix C++ compilation errors in generated skeleton by adding explicit
> pointer casts and using integer subtraction for offset calculation.
>
> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
> structs, ensuring C++ compilation compatibility while preserving C support
>
> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>       |         skel = skel_alloc(sizeof(*skel));
>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>       |                          |
>       |                          void*
>
> error: arithmetic on pointers to void
>       |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>       |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>       |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                                 sizeof(data) - 1);
>       |                                                 ~~~~~~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
> ---
> changelog:
> v3:
> - Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song
>
> v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
> - Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)
>
> v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
> ---
>  tools/bpf/bpftool/gen.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
> index 993c7d9484a4..010861b7d0ea 100644
> --- a/tools/bpf/bpftool/gen.c
> +++ b/tools/bpf/bpftool/gen.c
> @@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>                 {                                                           \n\
>                         struct %1$s *skel;                                  \n\
>                                                                             \n\
> -                       skel = skel_alloc(sizeof(*skel));                   \n\
> +                       skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
>                         if (!skel)                                          \n\
>                                 goto cleanup;                               \n\
> -                       skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
> +                       skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\

I'm wondering if this can also trigger some warnings under some
circumstances? void * is castable to long or unsigned long, but __u64
can be defined as long long (plus it's a question what happens on
32-bit architectures). Why worry about this if we can cast to `char *`
to calculate this size?

>                 ",
>                 obj_name, opts.data_sz);
>         bpf_object__for_each_map(map, obj) {
> @@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>                 \n\
>                 \";                                                         \n\
>                                                                             \n\
> +               #ifdef __cplusplus                                          \n\
> +                               skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\

we already use __typeof__() (see gen_st_ops_shadow_init), so let's use
that unconditionally without __cplusplus special casing

pw-bot: cr


> +               #else                                                       \n\
>                                 skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
> +               #endif                                                      \n\
>                                                                 sizeof(data) - 1);\n\
>                                 if (!skel->%1$s)                            \n\
>                                         goto cleanup;                       \n\
>                                 skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
>                         }                                                   \n\
> -                       ", ident, bpf_map_mmap_sz(map));
> +                       ", ident, bpf_map_mmap_sz(map), obj_name);
>         }
>         codegen("\
>                 \n\
> @@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>
>                 codegen("\
>                 \n\
> +               #ifdef __cplusplus                                          \n\
> +                       skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\

same as above, __typeof__ ?

> +               #else                                                       \n\
>                         skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
> +               #endif                                                      \n\
>                                                         %2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
>                         if (!skel->%1$s)                                    \n\
>                                 return -ENOMEM;                             \n\
>                         ",
> -                      ident, bpf_map_mmap_sz(map), mmap_flags);
> +                      ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
>         }
>         codegen("\
>                 \n\
> --
> 2.39.1
>
Re: [PATCH v3 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by Yonghong Song 1 month ago

On 1/3/26 6:14 PM, WanLi Niu wrote:
> From: WanLi Niu <niuwl1@chinatelecom.cn>
>
> Fix C++ compilation errors in generated skeleton by adding explicit
> pointer casts and using integer subtraction for offset calculation.
>
> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
> structs, ensuring C++ compilation compatibility while preserving C support
>
> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>        |         skel = skel_alloc(sizeof(*skel));
>        |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>        |                          |
>        |                          void*
>
> error: arithmetic on pointers to void
>        |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>        |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>        |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>        |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>        |                                                 sizeof(data) - 1);
>        |                                                 ~~~~~~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>        |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>        |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>        |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>        |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>

LGTM. Could you add a minimum reproducer in the commit message?

Acked-by: Yonghong Song <yonghong.song@linux.dev>
[PATCH v4 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by WanLi Niu 1 month ago
From: WanLi Niu <niuwl1@chinatelecom.cn>

Fix C++ compilation errors in generated skeleton by adding explicit
pointer casts and using integer subtraction for offset calculation.

Use struct outer::inner syntax under __cplusplus to access nested skeleton map
structs, ensuring C++ compilation compatibility while preserving C support

error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
      |         skel = skel_alloc(sizeof(*skel));
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~
      |                          |
      |                          void*

error: arithmetic on pointers to void
      |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
      |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                 sizeof(data) - 1);
      |                                                 ~~~~~~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
      |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Minimum reproducer:

	$ cat test.bpf.c
	int val; // placed in .bss section

	#include "vmlinux.h"
	#include <bpf/bpf_helpers.h>

	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }

	$ cat test.cpp
	#include <cerrno>

	extern "C" {
	#include "test.bpf.skel.h"
	}

	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
	$ g++ -c test.cpp -I.

Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
changelog:
v4:
- Add a minimum reproducer to demonstrate the issue, as suggested by Yonghong Song

v3: https://lore.kernel.org/all/20260104021402.2968-1-kiraskyler@163.com/
- Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song

v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
- Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)

v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
---
 tools/bpf/bpftool/gen.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 993c7d9484a4..010861b7d0ea 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		{							    \n\
 			struct %1$s *skel;				    \n\
 									    \n\
-			skel = skel_alloc(sizeof(*skel));		    \n\
+			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
 			if (!skel)					    \n\
 				goto cleanup;				    \n\
-			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
+			skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\
 		",
 		obj_name, opts.data_sz);
 	bpf_object__for_each_map(map, obj) {
@@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		\n\
 		\";							    \n\
 									    \n\
+		#ifdef __cplusplus                                          \n\
+				skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\
+		#else                                                       \n\
 				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
+		#endif							    \n\
 								sizeof(data) - 1);\n\
 				if (!skel->%1$s)			    \n\
 					goto cleanup;			    \n\
 				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
 			}						    \n\
-			", ident, bpf_map_mmap_sz(map));
+			", ident, bpf_map_mmap_sz(map), obj_name);
 	}
 	codegen("\
 		\n\
@@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 
 		codegen("\
 		\n\
+		#ifdef __cplusplus					    \n\
+			skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
+		#else							    \n\
 			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
+		#endif							    \n\
 							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
 			if (!skel->%1$s)				    \n\
 				return -ENOMEM;				    \n\
 			",
-		       ident, bpf_map_mmap_sz(map), mmap_flags);
+		       ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
 	}
 	codegen("\
 		\n\
-- 
2.39.1
Re: [PATCH v4 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by Jose E. Marchesi 1 month ago
FWIW I tested the reproducer with gcc-bpf and got no pointer conversion
warnings (not that I was expecting anything different, but just in
case):

 $ bpf-unknown-none-gcc -std=gnu11 -I./tools/include -g -O2 -c text.bpf.c -o test.bpf.o
 $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
 $ g++ -c test.cpp -I.

> From: WanLi Niu <niuwl1@chinatelecom.cn>
>
> Fix C++ compilation errors in generated skeleton by adding explicit
> pointer casts and using integer subtraction for offset calculation.
>
> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
> structs, ensuring C++ compilation compatibility while preserving C support
>
> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>       |         skel = skel_alloc(sizeof(*skel));
>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>       |                          |
>       |                          void*
>
> error: arithmetic on pointers to void
>       |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>       |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>       |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                                 sizeof(data) - 1);
>       |                                                 ~~~~~~~~~~~~~~~~~
>
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Minimum reproducer:
>
> 	$ cat test.bpf.c
> 	int val; // placed in .bss section
>
> 	#include "vmlinux.h"
> 	#include <bpf/bpf_helpers.h>
>
> 	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }
>
> 	$ cat test.cpp
> 	#include <cerrno>
>
> 	extern "C" {
> 	#include "test.bpf.skel.h"
> 	}
>
> 	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
> 	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
> 	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
> 	$ g++ -c test.cpp -I.
>
> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
> ---
> changelog:
> v4:
> - Add a minimum reproducer to demonstrate the issue, as suggested by Yonghong Song
>
> v3: https://lore.kernel.org/all/20260104021402.2968-1-kiraskyler@163.com/
> - Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song
>
> v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
> - Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)
>
> v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
> ---
>  tools/bpf/bpftool/gen.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
> index 993c7d9484a4..010861b7d0ea 100644
> --- a/tools/bpf/bpftool/gen.c
> +++ b/tools/bpf/bpftool/gen.c
> @@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>  		{							    \n\
>  			struct %1$s *skel;				    \n\
>  									    \n\
> -			skel = skel_alloc(sizeof(*skel));		    \n\
> +			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
>  			if (!skel)					    \n\
>  				goto cleanup;				    \n\
> -			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
> +			skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\
>  		",
>  		obj_name, opts.data_sz);
>  	bpf_object__for_each_map(map, obj) {
> @@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>  		\n\
>  		\";							    \n\
>  									    \n\
> +		#ifdef __cplusplus                                          \n\
> +				skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\
> +		#else                                                       \n\
>  				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
> +		#endif							    \n\
>  								sizeof(data) - 1);\n\
>  				if (!skel->%1$s)			    \n\
>  					goto cleanup;			    \n\
>  				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
>  			}						    \n\
> -			", ident, bpf_map_mmap_sz(map));
> +			", ident, bpf_map_mmap_sz(map), obj_name);
>  	}
>  	codegen("\
>  		\n\
> @@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>  
>  		codegen("\
>  		\n\
> +		#ifdef __cplusplus					    \n\
> +			skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
> +		#else							    \n\
>  			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
> +		#endif							    \n\
>  							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
>  			if (!skel->%1$s)				    \n\
>  				return -ENOMEM;				    \n\
>  			",
> -		       ident, bpf_map_mmap_sz(map), mmap_flags);
> +		       ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
>  	}
>  	codegen("\
>  		\n\
Re: [PATCH v4 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by WanLi Niu 1 month ago
> FWIW I tested the reproducer with gcc-bpf and got no pointer conversion
> warnings (not that I was expecting anything different, but just in
> case):
>
>  $ bpf-unknown-none-gcc -std=gnu11 -I./tools/include -g -O2 -c text.bpf.c -o test.bpf.o
>  $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
>  $ g++ -c test.cpp -I.

Thanks for testing.

The issue only occurs when bpftool gen skeleton is used in use_loader mode (bpftool gen skeleton -L|--use-loader).

Could you double-check if -L was included? I can reproduce the error reliably with it — here’s the full output:

$ rpm -qf `which bpf-unknown-none-gcc`
gcc-bpf-unknown-none-15.2.1-1.fc42.x86_64
$ bpf-unknown-none-gcc -std=gnu11 -I/usr/include -g -O2 -c test.bpf.c -o test.bpf.o
$ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
libbpf: elf: skipping section(2) .data (size 0)
libbpf: elf: skipping unrecognized data section(7) .comment
libbpf: prog 'handle': missing .BTF.ext line info for the main program, skipping all of .BTF.ext line info.
$ g++ -c test.cpp -I.
In file included from test.cpp:4:
test.bpf.skel.h: In function ‘test_bpf* test_bpf__open()’:
test.bpf.skel.h:65:26: error: invalid conversion from ‘void*’ to ‘test_bpf*’ [-fpermissive]
   65 |         skel = skel_alloc(sizeof(*skel));
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~
      |                          |
      |                          void*
test.bpf.skel.h:68:55: error: invalid use of ‘void’
   68 |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
      |                                                       ^~~~
test.bpf.skel.h:73:47: error: invalid conversion from ‘void*’ to ‘test_bpf::test_bpf__bss*’ [-fpermissive]
   73 |                 skel->bss = skel_prep_map_data((void *)data, 4096,
      |                             ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
      |                                               |
      |                                               void*
   74 |                                                 sizeof(data) - 1);
      |                                                 ~~~~~~~~~~~~~~~~~
test.bpf.skel.h: In function ‘int test_bpf__load(test_bpf*)’:
test.bpf.skel.h:196:43: error: invalid conversion from ‘void*’ to ‘test_bpf::test_bpf__bss*’ [-fpermissive]
  196 |         skel->bss = skel_finalize_map_data(&skel->maps.bss.initial_value,
      |                     ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                           |
      |                                           void*
  197 |                                         4096, PROT_READ | PROT_WRITE, skel->maps.bss.map_fd);
      |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ cat test.bpf.skel.h 
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
#ifndef __TEST_BPF_SKEL_H__
#define __TEST_BPF_SKEL_H__

#include <bpf/skel_internal.h>

struct test_bpf {
        struct bpf_loader_ctx ctx;
        struct {
                struct bpf_map_desc bss;
        } maps;
        struct {
                struct bpf_prog_desc handle;
        } progs;
        struct {
                int handle_fd;
        } links;
        struct test_bpf__bss {
                int val;
        } *bss;
};

static inline int
test_bpf__handle__attach(struct test_bpf *skel)
{
        int prog_fd = skel->progs.handle.prog_fd;
        int fd = skel_raw_tracepoint_open("sched_wakeup_new", prog_fd);

        if (fd > 0)
                skel->links.handle_fd = fd;
        return fd;
}

static inline int
test_bpf__attach(struct test_bpf *skel)
{
        int ret = 0;

        ret = ret < 0 ? ret : test_bpf__handle__attach(skel);
        return ret < 0 ? ret : 0;
}

static inline void
test_bpf__detach(struct test_bpf *skel)
{
        skel_closenz(skel->links.handle_fd);
}
static void
test_bpf__destroy(struct test_bpf *skel)
{
        if (!skel)
                return;
        test_bpf__detach(skel);
        skel_closenz(skel->progs.handle.prog_fd);
        skel_free_map_data(skel->bss, skel->maps.bss.initial_value, 4096);
        skel_closenz(skel->maps.bss.map_fd);
        skel_free(skel);
}
static inline struct test_bpf *
test_bpf__open(void)
{
        struct test_bpf *skel;

        skel = skel_alloc(sizeof(*skel));
        if (!skel)
                goto cleanup;
        skel->ctx.sz = (void *)&skel->links - (void *)skel;
        {
                static const char data[] __attribute__((__aligned__(8))) = "\
\0\0\0\0";

                skel->bss = skel_prep_map_data((void *)data, 4096,
                                                sizeof(data) - 1);
                if (!skel->bss)
                        goto cleanup;
                skel->maps.bss.initial_value = (__u64) (long) skel->bss;
        }
        return skel;
cleanup:
        test_bpf__destroy(skel);
        return NULL;
}

static inline int
test_bpf__load(struct test_bpf *skel)
{
        struct bpf_load_and_run_opts opts = {};
        int err;
        static const char opts_data[] __attribute__((__aligned__(8))) = "\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
\x18\0\0\0\0\0\0\0\x64\0\0\0\x64\0\0\0\x41\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\
\x18\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\
\x02\0\0\0\0\x13\0\0\0\0\0\0\x0e\x02\0\0\0\x01\0\0\0\x0c\0\0\0\x01\0\0\x0c\x01\
\0\0\0\x3c\0\0\0\x01\0\0\x0f\x04\0\0\0\x04\0\0\0\0\0\0\0\x04\0\0\0\0\x68\x61\
\x6e\x64\x6c\x65\0\x69\x6e\x74\0\x68\x61\x6e\x64\x6c\x65\0\x76\x61\x6c\0\0\x63\
\x74\x78\0\x72\x61\x77\x5f\x74\x72\x61\x63\x65\x70\x6f\x69\x6e\x74\x2f\x73\x63\
\x68\x65\x64\x5f\x77\x61\x6b\x65\x75\x70\x5f\x6e\x65\x77\0\x2e\x62\x73\x73\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\
\0\x04\0\0\0\x04\0\0\0\x01\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\x74\x65\x73\x74\x5f\
\x62\x70\x66\x2e\x62\x73\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\
\0\0\0\0\0\0\0\0\x05\0\0\0\x11\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x61\x6e\x64\x6c\x65\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\x10\0\0\0\0\0\0\0";
        static const char opts_insn[] __attribute__((__aligned__(8))) = "\
\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\
\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\
\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
\0\0\0\0\0\xd8\x05\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\
\0\0\0\0\0\0\0\xd4\x05\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\
\0\0\0\0\0\0\0\0\0\xc8\x05\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\x05\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\
\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xc0\x05\0\0\xb7\x03\0\0\x1c\0\0\0\
\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\
\xff\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x06\0\0\
\x63\x01\0\0\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\
\0\0\0\0\0\0\xec\x05\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\
\0\0\0\0\0\0\0\xe0\x05\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\
\0\0\0\0\0\xc5\x07\xc6\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\
\0\0\0\0\0\0\x79\x63\x20\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
\0\0\0\x28\x06\0\0\xb7\x02\0\0\x04\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\x01\
\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\
\x06\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\x06\0\0\x18\x61\0\
\0\0\0\0\0\0\0\0\0\x40\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
\x28\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x48\x06\0\0\x7b\x01\0\0\0\0\0\0\xb7\
\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x38\x06\0\0\xb7\x03\0\0\x20\0\0\
\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xa2\xff\0\0\0\0\x18\x60\0\0\
\0\0\0\0\0\0\0\0\x58\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x88\x06\0\0\x7b\x01\0\
\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x60\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
\x80\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x06\0\0\x18\
\x61\0\0\0\0\0\0\0\0\0\0\xc8\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
\0\0\0\x78\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd8\x06\0\0\x7b\x01\0\0\0\0\0\0\
\x18\x60\0\0\0\0\0\0\0\0\0\0\x78\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x06\0\
\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\
\0\0\0\0\xf0\x06\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\
\0\0\0\0\0\0\x90\x06\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\
\0\0\0\0\0\0\0\0\x94\x06\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\
\0\0\0\0\0\0\0\0\0\0\x98\x06\0\0\x7b\x01\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\
\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\x06\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\x05\0\
\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x78\x06\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\
\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x6d\xff\0\0\0\0\x63\x7a\x80\xff\0\0\0\0\
\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\
\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\
\0\0\0\0\0\0\0";
        opts.ctx = (struct bpf_loader_ctx *)skel;
        opts.data_sz = sizeof(opts_data) - 1;
        opts.data = (void *)opts_data;
        opts.insns_sz = sizeof(opts_insn) - 1;
        opts.insns = (void *)opts_insn;

        err = bpf_load_and_run(&opts);
        if (err < 0)
                return err;
        skel->bss = skel_finalize_map_data(&skel->maps.bss.initial_value,
                                        4096, PROT_READ | PROT_WRITE, skel->maps.bss.map_fd);
        if (!skel->bss)
                return -ENOMEM;
        return 0;
}

static inline struct test_bpf *
test_bpf__open_and_load(void)
{
        struct test_bpf *skel;

        skel = test_bpf__open();
        if (!skel)
                return NULL;
        if (test_bpf__load(skel)) {
                test_bpf__destroy(skel);
                return NULL;
        }
        return skel;
}

__attribute__((unused)) static void
test_bpf__assert(struct test_bpf *s __attribute__((unused)))
{
#ifdef __cplusplus
#define _Static_assert static_assert
#endif
        _Static_assert(sizeof(s->bss->val) == 4, "unexpected size of 'val'");
#ifdef __cplusplus
#undef _Static_assert
#endif
}

#endif /* __TEST_BPF_SKEL_H__ */

At 2026-01-05 19:50:25, "Jose E. Marchesi" <jose.marchesi@oracle.com> wrote:
>
>FWIW I tested the reproducer with gcc-bpf and got no pointer conversion
>warnings (not that I was expecting anything different, but just in
>case):
>
> $ bpf-unknown-none-gcc -std=gnu11 -I./tools/include -g -O2 -c text.bpf.c -o test.bpf.o
> $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
> $ g++ -c test.cpp -I.
>
>> From: WanLi Niu <niuwl1@chinatelecom.cn>
>>
>> Fix C++ compilation errors in generated skeleton by adding explicit
>> pointer casts and using integer subtraction for offset calculation.
>>
>> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
>> structs, ensuring C++ compilation compatibility while preserving C support
>>
>> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>>       |         skel = skel_alloc(sizeof(*skel));
>>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>>       |                          |
>>       |                          void*
>>
>> error: arithmetic on pointers to void
>>       |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>>       |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
>>
>> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>>       |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>>       |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>       |                                                 sizeof(data) - 1);
>>       |                                                 ~~~~~~~~~~~~~~~~~
>>
>> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>>       |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>>       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>       |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Minimum reproducer:
>>
>> 	$ cat test.bpf.c
>> 	int val; // placed in .bss section
>>
>> 	#include "vmlinux.h"
>> 	#include <bpf/bpf_helpers.h>
>>
>> 	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }
>>
>> 	$ cat test.cpp
>> 	#include <cerrno>
>>
>> 	extern "C" {
>> 	#include "test.bpf.skel.h"
>> 	}
>>
>> 	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>> 	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
>> 	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
>> 	$ g++ -c test.cpp -I.
>>
>> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
>> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
>> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
>> ---
>> changelog:
>> v4:
>> - Add a minimum reproducer to demonstrate the issue, as suggested by Yonghong Song
>>
>> v3: https://lore.kernel.org/all/20260104021402.2968-1-kiraskyler@163.com/
>> - Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song
>>
>> v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
>> - Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)
>>
>> v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
>> ---
>>  tools/bpf/bpftool/gen.c | 16 ++++++++++++----
>>  1 file changed, 12 insertions(+), 4 deletions(-)
>>
>> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
>> index 993c7d9484a4..010861b7d0ea 100644
>> --- a/tools/bpf/bpftool/gen.c
>> +++ b/tools/bpf/bpftool/gen.c
>> @@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>  		{							    \n\
>>  			struct %1$s *skel;				    \n\
>>  									    \n\
>> -			skel = skel_alloc(sizeof(*skel));		    \n\
>> +			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
>>  			if (!skel)					    \n\
>>  				goto cleanup;				    \n\
>> -			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
>> +			skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\
>>  		",
>>  		obj_name, opts.data_sz);
>>  	bpf_object__for_each_map(map, obj) {
>> @@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>  		\n\
>>  		\";							    \n\
>>  									    \n\
>> +		#ifdef __cplusplus                                          \n\
>> +				skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\
>> +		#else                                                       \n\
>>  				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
>> +		#endif							    \n\
>>  								sizeof(data) - 1);\n\
>>  				if (!skel->%1$s)			    \n\
>>  					goto cleanup;			    \n\
>>  				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
>>  			}						    \n\
>> -			", ident, bpf_map_mmap_sz(map));
>> +			", ident, bpf_map_mmap_sz(map), obj_name);
>>  	}
>>  	codegen("\
>>  		\n\
>> @@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>  
>>  		codegen("\
>>  		\n\
>> +		#ifdef __cplusplus					    \n\
>> +			skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
>> +		#else							    \n\
>>  			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
>> +		#endif							    \n\
>>  							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
>>  			if (!skel->%1$s)				    \n\
>>  				return -ENOMEM;				    \n\
>>  			",
>> -		       ident, bpf_map_mmap_sz(map), mmap_flags);
>> +		       ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
>>  	}
>>  	codegen("\
>>  		\n\
Re: [PATCH v4 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by Jose E. Marchesi 1 month ago
>> FWIW I tested the reproducer with gcc-bpf and got no pointer conversion
>> warnings (not that I was expecting anything different, but just in
>> case):
>>
>>  $ bpf-unknown-none-gcc -std=gnu11 -I./tools/include -g -O2 -c text.bpf.c -o test.bpf.o
>>  $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
>>  $ g++ -c test.cpp -I.
>
> Thanks for testing.
>
> The issue only occurs when bpftool gen skeleton is used in use_loader
> mode (bpftool gen skeleton -L|--use-loader).
>
> Could you double-check if -L was included? I can reproduce the error
> reliably with it — here’s the full output:

I meant to say that I tested the reproducer _with your patch applied_.
It indeed cures the issue :)

Sorry it wasn't clear.

>
> $ rpm -qf `which bpf-unknown-none-gcc`
> gcc-bpf-unknown-none-15.2.1-1.fc42.x86_64
> $ bpf-unknown-none-gcc -std=gnu11 -I/usr/include -g -O2 -c test.bpf.c -o test.bpf.o
> $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
> libbpf: elf: skipping section(2) .data (size 0)
> libbpf: elf: skipping unrecognized data section(7) .comment
> libbpf: prog 'handle': missing .BTF.ext line info for the main program, skipping all of .BTF.ext line info.
> $ g++ -c test.cpp -I.
> In file included from test.cpp:4:
> test.bpf.skel.h: In function ‘test_bpf* test_bpf__open()’:
> test.bpf.skel.h:65:26: error: invalid conversion from ‘void*’ to ‘test_bpf*’ [-fpermissive]
>    65 |         skel = skel_alloc(sizeof(*skel));
>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>       |                          |
>       |                          void*
> test.bpf.skel.h:68:55: error: invalid use of ‘void’
>    68 |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>       |                                                       ^~~~
> test.bpf.skel.h:73:47: error: invalid conversion from ‘void*’ to ‘test_bpf::test_bpf__bss*’ [-fpermissive]
>    73 |                 skel->bss = skel_prep_map_data((void *)data, 4096,
>       |                             ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
>       |                                               |
>       |                                               void*
>    74 |                                                 sizeof(data) - 1);
>       |                                                 ~~~~~~~~~~~~~~~~~
> test.bpf.skel.h: In function ‘int test_bpf__load(test_bpf*)’:
> test.bpf.skel.h:196:43: error: invalid conversion from ‘void*’ to ‘test_bpf::test_bpf__bss*’ [-fpermissive]
>   196 |         skel->bss = skel_finalize_map_data(&skel->maps.bss.initial_value,
>       |                     ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                           |
>       |                                           void*
>   197 |                                         4096, PROT_READ | PROT_WRITE, skel->maps.bss.map_fd);
>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> $ cat test.bpf.skel.h 
> /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
> /* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
> #ifndef __TEST_BPF_SKEL_H__
> #define __TEST_BPF_SKEL_H__
>
> #include <bpf/skel_internal.h>
>
> struct test_bpf {
>         struct bpf_loader_ctx ctx;
>         struct {
>                 struct bpf_map_desc bss;
>         } maps;
>         struct {
>                 struct bpf_prog_desc handle;
>         } progs;
>         struct {
>                 int handle_fd;
>         } links;
>         struct test_bpf__bss {
>                 int val;
>         } *bss;
> };
>
> static inline int
> test_bpf__handle__attach(struct test_bpf *skel)
> {
>         int prog_fd = skel->progs.handle.prog_fd;
>         int fd = skel_raw_tracepoint_open("sched_wakeup_new", prog_fd);
>
>         if (fd > 0)
>                 skel->links.handle_fd = fd;
>         return fd;
> }
>
> static inline int
> test_bpf__attach(struct test_bpf *skel)
> {
>         int ret = 0;
>
>         ret = ret < 0 ? ret : test_bpf__handle__attach(skel);
>         return ret < 0 ? ret : 0;
> }
>
> static inline void
> test_bpf__detach(struct test_bpf *skel)
> {
>         skel_closenz(skel->links.handle_fd);
> }
> static void
> test_bpf__destroy(struct test_bpf *skel)
> {
>         if (!skel)
>                 return;
>         test_bpf__detach(skel);
>         skel_closenz(skel->progs.handle.prog_fd);
>         skel_free_map_data(skel->bss, skel->maps.bss.initial_value, 4096);
>         skel_closenz(skel->maps.bss.map_fd);
>         skel_free(skel);
> }
> static inline struct test_bpf *
> test_bpf__open(void)
> {
>         struct test_bpf *skel;
>
>         skel = skel_alloc(sizeof(*skel));
>         if (!skel)
>                 goto cleanup;
>         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>         {
>                 static const char data[] __attribute__((__aligned__(8))) = "\
> \0\0\0\0";
>
>                 skel->bss = skel_prep_map_data((void *)data, 4096,
>                                                 sizeof(data) - 1);
>                 if (!skel->bss)
>                         goto cleanup;
>                 skel->maps.bss.initial_value = (__u64) (long) skel->bss;
>         }
>         return skel;
> cleanup:
>         test_bpf__destroy(skel);
>         return NULL;
> }
>
> static inline int
> test_bpf__load(struct test_bpf *skel)
> {
>         struct bpf_load_and_run_opts opts = {};
>         int err;
>         static const char opts_data[] __attribute__((__aligned__(8))) = "\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
> \x18\0\0\0\0\0\0\0\x64\0\0\0\x64\0\0\0\x41\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\
> \x18\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\
> \x02\0\0\0\0\x13\0\0\0\0\0\0\x0e\x02\0\0\0\x01\0\0\0\x0c\0\0\0\x01\0\0\x0c\x01\
> \0\0\0\x3c\0\0\0\x01\0\0\x0f\x04\0\0\0\x04\0\0\0\0\0\0\0\x04\0\0\0\0\x68\x61\
> \x6e\x64\x6c\x65\0\x69\x6e\x74\0\x68\x61\x6e\x64\x6c\x65\0\x76\x61\x6c\0\0\x63\
> \x74\x78\0\x72\x61\x77\x5f\x74\x72\x61\x63\x65\x70\x6f\x69\x6e\x74\x2f\x73\x63\
> \x68\x65\x64\x5f\x77\x61\x6b\x65\x75\x70\x5f\x6e\x65\x77\0\x2e\x62\x73\x73\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\
> \0\x04\0\0\0\x04\0\0\0\x01\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\x74\x65\x73\x74\x5f\
> \x62\x70\x66\x2e\x62\x73\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\
> \0\0\0\0\0\0\0\0\x05\0\0\0\x11\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x61\x6e\x64\x6c\x65\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
> \0\0\0\x10\0\0\0\0\0\0\0";
>         static const char opts_insn[] __attribute__((__aligned__(8))) = "\
> \xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
> \0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\
> \xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
> \0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
> \x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
> \x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\
> \xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
> \0\0\0\0\0\xd8\x05\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\
> \0\0\0\0\0\0\0\xd4\x05\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\
> \0\0\0\0\0\0\0\0\0\xc8\x05\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
> \0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\x05\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\
> \0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xc0\x05\0\0\xb7\x03\0\0\x1c\0\0\0\
> \x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\
> \xff\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x06\0\0\
> \x63\x01\0\0\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\
> \0\0\0\0\0\0\xec\x05\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\
> \0\0\0\0\0\0\0\xe0\x05\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\
> \0\0\0\0\0\xc5\x07\xc6\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\
> \0\0\0\0\0\0\x79\x63\x20\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
> \0\0\0\x28\x06\0\0\xb7\x02\0\0\x04\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\x01\
> \0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\0\0\
> \0\0\0\0\0\0\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\
> \x06\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\x06\0\0\x18\x61\0\
> \0\0\0\0\0\0\0\0\0\x40\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
> \x28\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x48\x06\0\0\x7b\x01\0\0\0\0\0\0\xb7\
> \x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x38\x06\0\0\xb7\x03\0\0\x20\0\0\
> \0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xa2\xff\0\0\0\0\x18\x60\0\0\
> \0\0\0\0\0\0\0\0\x58\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x88\x06\0\0\x7b\x01\0\
> \0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x60\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
> \x80\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x06\0\0\x18\
> \x61\0\0\0\0\0\0\0\0\0\0\xc8\x06\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
> \0\0\0\x78\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd8\x06\0\0\x7b\x01\0\0\0\0\0\0\
> \x18\x60\0\0\0\0\0\0\0\0\0\0\x78\x06\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x06\0\
> \0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\
> \0\0\0\0\xf0\x06\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\
> \0\0\0\0\0\0\x90\x06\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\
> \0\0\0\0\0\0\0\0\x94\x06\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\
> \0\0\0\0\0\0\0\0\0\0\x98\x06\0\0\x7b\x01\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\
> \x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\x06\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\x05\0\
> \0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x78\x06\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\
> \xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x6d\xff\0\0\0\0\x63\x7a\x80\xff\0\0\0\0\
> \x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\
> \xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
> \0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\
> \0\0\0\0\0\0\0";
>         opts.ctx = (struct bpf_loader_ctx *)skel;
>         opts.data_sz = sizeof(opts_data) - 1;
>         opts.data = (void *)opts_data;
>         opts.insns_sz = sizeof(opts_insn) - 1;
>         opts.insns = (void *)opts_insn;
>
>         err = bpf_load_and_run(&opts);
>         if (err < 0)
>                 return err;
>         skel->bss = skel_finalize_map_data(&skel->maps.bss.initial_value,
>                                         4096, PROT_READ | PROT_WRITE, skel->maps.bss.map_fd);
>         if (!skel->bss)
>                 return -ENOMEM;
>         return 0;
> }
>
> static inline struct test_bpf *
> test_bpf__open_and_load(void)
> {
>         struct test_bpf *skel;
>
>         skel = test_bpf__open();
>         if (!skel)
>                 return NULL;
>         if (test_bpf__load(skel)) {
>                 test_bpf__destroy(skel);
>                 return NULL;
>         }
>         return skel;
> }
>
> __attribute__((unused)) static void
> test_bpf__assert(struct test_bpf *s __attribute__((unused)))
> {
> #ifdef __cplusplus
> #define _Static_assert static_assert
> #endif
>         _Static_assert(sizeof(s->bss->val) == 4, "unexpected size of 'val'");
> #ifdef __cplusplus
> #undef _Static_assert
> #endif
> }
>
> #endif /* __TEST_BPF_SKEL_H__ */
>
> At 2026-01-05 19:50:25, "Jose E. Marchesi" <jose.marchesi@oracle.com> wrote:
>>
>>FWIW I tested the reproducer with gcc-bpf and got no pointer conversion
>>warnings (not that I was expecting anything different, but just in
>>case):
>>
>> $ bpf-unknown-none-gcc -std=gnu11 -I./tools/include -g -O2 -c text.bpf.c -o test.bpf.o
>> $ bpftool gen skeleton test.bpf.o -L > test.bpf.skel.h
>> $ g++ -c test.cpp -I.
>>
>>> From: WanLi Niu <niuwl1@chinatelecom.cn>
>>>
>>> Fix C++ compilation errors in generated skeleton by adding explicit
>>> pointer casts and using integer subtraction for offset calculation.
>>>
>>> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
>>> structs, ensuring C++ compilation compatibility while preserving C support
>>>
>>> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>>>       |         skel = skel_alloc(sizeof(*skel));
>>>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>>>       |                          |
>>>       |                          void*
>>>
>>> error: arithmetic on pointers to void
>>>       |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>>>       |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
>>>
>>> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>>>       |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>>>       |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>       |                                                 sizeof(data) - 1);
>>>       |                                                 ~~~~~~~~~~~~~~~~~
>>>
>>> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>>>       |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>>>       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>       |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>>>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>
>>> Minimum reproducer:
>>>
>>> 	$ cat test.bpf.c
>>> 	int val; // placed in .bss section
>>>
>>> 	#include "vmlinux.h"
>>> 	#include <bpf/bpf_helpers.h>
>>>
>>> 	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }
>>>
>>> 	$ cat test.cpp
>>> 	#include <cerrno>
>>>
>>> 	extern "C" {
>>> 	#include "test.bpf.skel.h"
>>> 	}
>>>
>>> 	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>>> 	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
>>> 	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
>>> 	$ g++ -c test.cpp -I.
>>>
>>> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
>>> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
>>> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
>>> ---
>>> changelog:
>>> v4:
>>> - Add a minimum reproducer to demonstrate the issue, as suggested by Yonghong Song
>>>
>>> v3: https://lore.kernel.org/all/20260104021402.2968-1-kiraskyler@163.com/
>>> - Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song
>>>
>>> v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
>>> - Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)
>>>
>>> v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
>>> ---
>>>  tools/bpf/bpftool/gen.c | 16 ++++++++++++----
>>>  1 file changed, 12 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
>>> index 993c7d9484a4..010861b7d0ea 100644
>>> --- a/tools/bpf/bpftool/gen.c
>>> +++ b/tools/bpf/bpftool/gen.c
>>> @@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>>  		{							    \n\
>>>  			struct %1$s *skel;				    \n\
>>>  									    \n\
>>> -			skel = skel_alloc(sizeof(*skel));		    \n\
>>> +			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
>>>  			if (!skel)					    \n\
>>>  				goto cleanup;				    \n\
>>> -			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
>>> +			skel->ctx.sz = (__u64)&skel->links - (__u64)skel;   \n\
>>>  		",
>>>  		obj_name, opts.data_sz);
>>>  	bpf_object__for_each_map(map, obj) {
>>> @@ -755,13 +755,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>>  		\n\
>>>  		\";							    \n\
>>>  									    \n\
>>> +		#ifdef __cplusplus                                          \n\
>>> +				skel->%1$s = (struct %3$s::%3$s__%1$s *)skel_prep_map_data((void *)data, %2$zd,\n\
>>> +		#else                                                       \n\
>>>  				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
>>> +		#endif							    \n\
>>>  								sizeof(data) - 1);\n\
>>>  				if (!skel->%1$s)			    \n\
>>>  					goto cleanup;			    \n\
>>>  				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
>>>  			}						    \n\
>>> -			", ident, bpf_map_mmap_sz(map));
>>> +			", ident, bpf_map_mmap_sz(map), obj_name);
>>>  	}
>>>  	codegen("\
>>>  		\n\
>>> @@ -857,12 +861,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>>>  
>>>  		codegen("\
>>>  		\n\
>>> +		#ifdef __cplusplus					    \n\
>>> +			skel->%1$s = (struct %4$s::%4$s__%1$s *)skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
>>> +		#else							    \n\
>>>  			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
>>> +		#endif							    \n\
>>>  							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
>>>  			if (!skel->%1$s)				    \n\
>>>  				return -ENOMEM;				    \n\
>>>  			",
>>> -		       ident, bpf_map_mmap_sz(map), mmap_flags);
>>> +		       ident, bpf_map_mmap_sz(map), mmap_flags, obj_name);
>>>  	}
>>>  	codegen("\
>>>  		\n\
Re: [PATCH v4 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by Quentin Monnet 1 month ago
On 05/01/2026 07:12, WanLi Niu wrote:
> From: WanLi Niu <niuwl1@chinatelecom.cn>
> 
> Fix C++ compilation errors in generated skeleton by adding explicit
> pointer casts and using integer subtraction for offset calculation.
> 
> Use struct outer::inner syntax under __cplusplus to access nested skeleton map
> structs, ensuring C++ compilation compatibility while preserving C support
> 
> error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
>       |         skel = skel_alloc(sizeof(*skel));
>       |                ~~~~~~~~~~^~~~~~~~~~~~~~~
>       |                          |
>       |                          void*
> 
> error: arithmetic on pointers to void
>       |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
>       |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
> 
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
>       |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                                 sizeof(data) - 1);
>       |                                                 ~~~~~~~~~~~~~~~~~
> 
> error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
>       |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
>       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
>       |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> Minimum reproducer:
> 
> 	$ cat test.bpf.c
> 	int val; // placed in .bss section
> 
> 	#include "vmlinux.h"
> 	#include <bpf/bpf_helpers.h>
> 
> 	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }
> 
> 	$ cat test.cpp
> 	#include <cerrno>
> 
> 	extern "C" {
> 	#include "test.bpf.skel.h"
> 	}
> 
> 	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
> 	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
> 	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
> 	$ g++ -c test.cpp -I.


I tried it and could confirm that the warnings are gone.


> Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
> Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>


Acked-by: Quentin Monnet <qmo@kernel.org>

Thank you!
[PATCH v5 bpf-next] bpftool: Make skeleton C++ compatible with explicit casts
Posted by WanLi Niu 1 month ago
From: WanLi Niu <niuwl1@chinatelecom.cn>

Fix C++ compilation errors in generated skeleton by adding explicit
pointer casts and use char * subtraction for offset calculation

error: invalid conversion from 'void*' to '<obj_name>*' [-fpermissive]
      |         skel = skel_alloc(sizeof(*skel));
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~
      |                          |
      |                          void*

error: arithmetic on pointers to void
      |         skel->ctx.sz = (void *)&skel->links - (void *)skel;
      |                        ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |                 skel-><ident> = skel_prep_map_data((void *)data, 4096,
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                 sizeof(data) - 1);
      |                                                 ~~~~~~~~~~~~~~~~~

error: assigning to 'struct <obj_name>__<ident> *' from incompatible type 'void *'
      |         skel-><ident> = skel_finalize_map_data(&skel->maps.<ident>.initial_value,
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                         4096, PROT_READ | PROT_WRITE, skel->maps.<ident>.map_fd);
      |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Minimum reproducer:

	$ cat test.bpf.c
	int val; // placed in .bss section

	#include "vmlinux.h"
	#include <bpf/bpf_helpers.h>

	SEC("raw_tracepoint/sched_wakeup_new") int handle(void *ctx) { return 0; }

	$ cat test.cpp
	#include <cerrno>

	extern "C" {
	#include "test.bpf.skel.h"
	}

	$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
	$ clang -g -O2 -target bpf -c test.bpf.c -o test.bpf.o
	$ bpftool gen skeleton test.bpf.o -L  > test.bpf.skel.h
	$ g++ -c test.cpp -I.

Signed-off-by: WanLi Niu <niuwl1@chinatelecom.cn>
Co-developed-by: Menglong Dong <dongml2@chinatelecom.cn>
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
changelog:
v5:
- Use char * arithmetic instead of integer subtraction for offsets as suggested by Andrii Nakryiko
- Use __typeof__() without __cplusplus special casing as suggested by Andrii Nakryiko

v4: https://lore.kernel.org/all/20260105071231.2501-1-kiraskyler@163.com/
- Add a minimum reproducer to demonstrate the issue, as suggested by Yonghong Song

v3: https://lore.kernel.org/all/20260104021402.2968-1-kiraskyler@163.com/
- Fix two additional <obj_name>__<ident> type mismatches as suggested by Yonghong Song

v2: https://lore.kernel.org/all/20251231102929.3843-1-kiraskyler@163.com/
- Use generic (struct %1$s *) instead of project-specific (struct trace_bpf *)

v1: https://lore.kernel.org/all/20251231092541.3352-1-kiraskyler@163.com/
---
 tools/bpf/bpftool/gen.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 993c7d9484a4..2f9e10752e28 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -731,10 +731,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		{							    \n\
 			struct %1$s *skel;				    \n\
 									    \n\
-			skel = skel_alloc(sizeof(*skel));		    \n\
+			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
 			if (!skel)					    \n\
 				goto cleanup;				    \n\
-			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
+			skel->ctx.sz = (char *)&skel->links - (char *)skel; \n\
 		",
 		obj_name, opts.data_sz);
 	bpf_object__for_each_map(map, obj) {
@@ -755,7 +755,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		\n\
 		\";							    \n\
 									    \n\
-				skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\
+				skel->%1$s = (__typeof__(skel->%1$s))skel_prep_map_data((void *)data, %2$zd,\n\
 								sizeof(data) - 1);\n\
 				if (!skel->%1$s)			    \n\
 					goto cleanup;			    \n\
@@ -857,7 +857,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 
 		codegen("\
 		\n\
-			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
+			skel->%1$s = (__typeof__(skel->%1$s))skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
 							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
 			if (!skel->%1$s)				    \n\
 				return -ENOMEM;				    \n\
-- 
2.39.1