[PATCH bpf v2 4/4] selftests/bpf: Add test for showing a void BTF type

From: Jiayuan Chen

Date: Sun Aug 30 2026 - 03:35:06 EST


Call bpf_snprintf_btf() with the type_id of a "const void" from the
vmlinux BTF and check the rendered output is the "<unsupported kind:0>"
placeholder. On an unfixed kernel this used to NULL-deref in
btf_modifier_show(), so the test doubles as a reproducer: it oopses the
task (and panics it under panic_on_oops).

Signed-off-by: Jiayuan Chen <jiayuan.chen@xxxxxxxxx>
---
.../selftests/bpf/prog_tests/btf_show_void.c | 57 +++++++++++++++++++
.../selftests/bpf/progs/btf_show_void.c | 22 +++++++
2 files changed, 79 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_show_void.c
create mode 100644 tools/testing/selftests/bpf/progs/btf_show_void.c

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_show_void.c b/tools/testing/selftests/bpf/prog_tests/btf_show_void.c
new file mode 100644
index 000000000000..546833199195
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/btf_show_void.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <bpf/btf.h>
+#include "btf_show_void.skel.h"
+
+/*
+ * bpf_snprintf_btf() with the type_id of a "const void" (a modifier that
+ * resolves to void, present in the vmlinux BTF) used to NULL-deref in
+ * btf_modifier_show(). A fixed kernel prints the "<unsupported kind:0>"
+ * placeholder; on an unfixed kernel this oopses the task (and panics it under
+ * panic_on_oops), so it doubles as a reproducer.
+ */
+void test_btf_show_void(void)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ const struct btf_type *t;
+ struct btf_show_void *skel;
+ int i, n, cv = 0, err;
+ char ctx[16] = {};
+ struct btf *btf;
+
+ btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+ if (!ASSERT_OK_PTR(btf, "btf__parse vmlinux"))
+ return;
+
+ n = btf__type_cnt(btf);
+ for (i = 1; i < n; i++) {
+ t = btf__type_by_id(btf, i);
+ if (btf_kind(t) == BTF_KIND_CONST && t->type == 0) {
+ cv = i;
+ break;
+ }
+ }
+ if (!ASSERT_GT(cv, 0, "find const void in vmlinux BTF"))
+ goto out_btf;
+
+ skel = btf_show_void__open();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ goto out_btf;
+ skel->rodata->const_void_id = cv;
+ if (!ASSERT_OK(btf_show_void__load(skel), "skel_load"))
+ goto out_skel;
+
+ topts.ctx_in = ctx;
+ topts.ctx_size_in = sizeof(ctx);
+ err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.dump_const_void),
+ &topts);
+ if (!ASSERT_OK(err, "test_run"))
+ goto out_skel;
+
+ ASSERT_EQ(skel->bss->ret, sizeof("<unsupported kind:0>") - 1, "ret");
+ ASSERT_STREQ(skel->bss->out, "<unsupported kind:0>", "placeholder");
+out_skel:
+ btf_show_void__destroy(skel);
+out_btf:
+ btf__free(btf);
+}
diff --git a/tools/testing/selftests/bpf/progs/btf_show_void.c b/tools/testing/selftests/bpf/progs/btf_show_void.c
new file mode 100644
index 000000000000..9fabd7372f89
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf_show_void.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "btf_ptr.h"
+#include <bpf/bpf_helpers.h>
+
+const volatile __u32 const_void_id;
+char out[64];
+long ret;
+
+SEC("raw_tp/sys_enter")
+int dump_const_void(void *ctx)
+{
+ struct btf_ptr ptr = {
+ .ptr = ctx,
+ .type_id = const_void_id,
+ .flags = 0,
+ };
+
+ ret = bpf_snprintf_btf(out, sizeof(out), &ptr, sizeof(ptr), 0);
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.43.0