* [PATCH bpf-next v2 1/4] selftests/bpf: fix __jited_unpriv tag name
2026-03-31 0:59 [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
@ 2026-03-31 0:59 ` Eduard Zingerman
2026-03-31 0:59 ` [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix Eduard Zingerman
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 0:59 UTC (permalink / raw)
To: bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Eduard Zingerman, Ihor Solodrai
__jited_unpriv was using "test_jited=" as its tag name, same as the
priv variant __jited. Fix by using "test_jited_unpriv=".
Fixes: 7d743e4c759c ("selftests/bpf: __jited test tag to check disassembly after jit")
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 0904fe14ad1d45aba2f2c8a9a12881a0d248685e..52cf9f3cccd0ccd8034b9786d787e53992a4a6d8 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -140,7 +140,7 @@
#define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg)))
+#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv")))
#define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv")))
#define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix
2026-03-31 0:59 [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
2026-03-31 0:59 ` [PATCH bpf-next v2 1/4] selftests/bpf: fix __jited_unpriv tag name Eduard Zingerman
@ 2026-03-31 0:59 ` Eduard Zingerman
2026-03-31 12:07 ` Mykyta Yatsenko
2026-03-31 0:59 ` [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 0:59 UTC (permalink / raw)
To: bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Eduard Zingerman, Ihor Solodrai
Change str_has_pfx() to return a pointer to the first character after
the prefix, thus eliminating the repetitive (s + sizeof(PFX) - 1)
patterns.
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/test_loader.c | 51 ++++++++++++++-----------------
1 file changed, 23 insertions(+), 28 deletions(-)
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 338c035c36884c02ac57cd17110122c10b4858e4..50ca1b6ec8150efe2cb280667af9ac4972c28657 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -11,8 +11,12 @@
#include "cap_helpers.h"
#include "jit_disasm_helpers.h"
-#define str_has_pfx(str, pfx) \
- (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
+static inline const char *str_has_pfx(const char *str, const char *pfx)
+{
+ size_t len = strlen(pfx);
+
+ return strncmp(str, pfx, len) == 0 ? str + len : NULL;
+}
#define TEST_LOADER_LOG_BUF_SZ 2097152
@@ -161,21 +165,21 @@ static void free_test_spec(struct test_spec *spec)
static int compile_regex(const char *pattern, regex_t *regex)
{
char err_buf[256], buf[256] = {}, *ptr, *buf_end;
- const char *original_pattern = pattern;
+ const char *original_pattern = pattern, *m;
bool in_regex = false;
int err;
buf_end = buf + sizeof(buf);
ptr = buf;
while (*pattern && ptr < buf_end - 2) {
- if (!in_regex && str_has_pfx(pattern, "{{")) {
+ if (!in_regex && (m = str_has_pfx(pattern, "{{"))) {
in_regex = true;
- pattern += 2;
+ pattern = m;
continue;
}
- if (in_regex && str_has_pfx(pattern, "}}")) {
+ if (in_regex && (m = str_has_pfx(pattern, "}}"))) {
in_regex = false;
- pattern += 2;
+ pattern = m;
continue;
}
if (in_regex) {
@@ -452,8 +456,8 @@ static int parse_test_spec(struct test_loader *tester,
continue;
s = btf__str_by_offset(btf, t->name_off);
- if (str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX)) {
- description = s + sizeof(TEST_TAG_DESCRIPTION_PFX) - 1;
+ if ((val = str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX))) {
+ description = val;
} else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
spec->priv.expect_failure = true;
spec->mode_mask |= PRIV;
@@ -530,29 +534,24 @@ static int parse_test_spec(struct test_loader *tester,
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX)) {
- val = s + sizeof(TEST_TAG_RETVAL_PFX) - 1;
+ } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX))) {
err = parse_retval(val, &spec->priv.retval, "__retval");
if (err)
goto cleanup;
spec->priv.execute = true;
spec->mode_mask |= PRIV;
- } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV)) {
- val = s + sizeof(TEST_TAG_RETVAL_PFX_UNPRIV) - 1;
+ } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV))) {
err = parse_retval(val, &spec->unpriv.retval, "__retval_unpriv");
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
spec->unpriv.execute = true;
has_unpriv_retval = true;
- } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
- val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1;
+ } else if ((val = str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX))) {
err = parse_int(val, &spec->log_level, "test log level");
if (err)
goto cleanup;
- } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) {
- val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1;
-
+ } else if ((val = str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX))) {
clear = val[0] == '!';
if (clear)
val++;
@@ -577,8 +576,7 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
update_flags(&spec->prog_flags, flags, clear);
}
- } else if (str_has_pfx(s, TEST_TAG_ARCH)) {
- val = s + sizeof(TEST_TAG_ARCH) - 1;
+ } else if ((val = str_has_pfx(s, TEST_TAG_ARCH))) {
if (strcmp(val, "X86_64") == 0) {
arch = ARCH_X86_64;
} else if (strcmp(val, "ARM64") == 0) {
@@ -596,16 +594,14 @@ static int parse_test_spec(struct test_loader *tester,
collect_jit = get_current_arch() == arch;
unpriv_jit_on_next_line = true;
jit_on_next_line = true;
- } else if (str_has_pfx(s, TEST_BTF_PATH)) {
- spec->btf_custom_path = s + sizeof(TEST_BTF_PATH) - 1;
- } else if (str_has_pfx(s, TEST_TAG_CAPS_UNPRIV)) {
- val = s + sizeof(TEST_TAG_CAPS_UNPRIV) - 1;
+ } else if ((val = str_has_pfx(s, TEST_BTF_PATH))) {
+ spec->btf_custom_path = val;
+ } else if ((val = str_has_pfx(s, TEST_TAG_CAPS_UNPRIV))) {
err = parse_caps(val, &spec->unpriv.caps, "test caps");
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if (str_has_pfx(s, TEST_TAG_LOAD_MODE_PFX)) {
- val = s + sizeof(TEST_TAG_LOAD_MODE_PFX) - 1;
+ } else if ((val = str_has_pfx(s, TEST_TAG_LOAD_MODE_PFX))) {
if (strcmp(val, "jited") == 0) {
load_mask = JITED;
} else if (strcmp(val, "no_jited") == 0) {
@@ -635,12 +631,11 @@ static int parse_test_spec(struct test_loader *tester,
&spec->unpriv.stdout);
if (err)
goto cleanup;
- } else if (str_has_pfx(s, TEST_TAG_LINEAR_SIZE)) {
+ } else if ((val = str_has_pfx(s, TEST_TAG_LINEAR_SIZE))) {
switch (bpf_program__type(prog)) {
case BPF_PROG_TYPE_SCHED_ACT:
case BPF_PROG_TYPE_SCHED_CLS:
case BPF_PROG_TYPE_CGROUP_SKB:
- val = s + sizeof(TEST_TAG_LINEAR_SIZE) - 1;
err = parse_int(val, &spec->linear_sz, "test linear size");
if (err)
goto cleanup;
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix
2026-03-31 0:59 ` [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix Eduard Zingerman
@ 2026-03-31 12:07 ` Mykyta Yatsenko
2026-03-31 17:52 ` Eduard Zingerman
0 siblings, 1 reply; 11+ messages in thread
From: Mykyta Yatsenko @ 2026-03-31 12:07 UTC (permalink / raw)
To: Eduard Zingerman, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Ihor Solodrai
On 3/31/26 1:59 AM, Eduard Zingerman wrote:
> Change str_has_pfx() to return a pointer to the first character after
> the prefix, thus eliminating the repetitive (s + sizeof(PFX) - 1)
> patterns.
>
> Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
> tools/testing/selftests/bpf/test_loader.c | 51 ++++++++++++++-----------------
> 1 file changed, 23 insertions(+), 28 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
> index 338c035c36884c02ac57cd17110122c10b4858e4..50ca1b6ec8150efe2cb280667af9ac4972c28657 100644
> --- a/tools/testing/selftests/bpf/test_loader.c
> +++ b/tools/testing/selftests/bpf/test_loader.c
> @@ -11,8 +11,12 @@
> #include "cap_helpers.h"
> #include "jit_disasm_helpers.h"
>
> -#define str_has_pfx(str, pfx) \
> - (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
> +static inline const char *str_has_pfx(const char *str, const char *pfx)
> +{
> + size_t len = strlen(pfx);
> +
> + return strncmp(str, pfx, len) == 0 ? str + len : NULL;
> +}
>
> #define TEST_LOADER_LOG_BUF_SZ 2097152
>
> @@ -161,21 +165,21 @@ static void free_test_spec(struct test_spec *spec)
> static int compile_regex(const char *pattern, regex_t *regex)
> {
> char err_buf[256], buf[256] = {}, *ptr, *buf_end;
> - const char *original_pattern = pattern;
> + const char *original_pattern = pattern, *m;
super nit: what does m stand for? Something like `next` would do better,
wouldn't it?
Overall refactoring looks correct, all callsites of the str_has_pfx()
are modified, except one in parse_int(), but it's correct anyways.
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
> bool in_regex = false;
> int err;
>
> buf_end = buf + sizeof(buf);
> ptr = buf;
> while (*pattern && ptr < buf_end - 2) {
> - if (!in_regex && str_has_pfx(pattern, "{{")) {
> + if (!in_regex && (m = str_has_pfx(pattern, "{{"))) {
> in_regex = true;
> - pattern += 2;
> + pattern = m;
> continue;
> }
> - if (in_regex && str_has_pfx(pattern, "}}")) {
> + if (in_regex && (m = str_has_pfx(pattern, "}}"))) {
> in_regex = false;
> - pattern += 2;
> + pattern = m;
> continue;
> }
> if (in_regex) {
> @@ -452,8 +456,8 @@ static int parse_test_spec(struct test_loader *tester,
> continue;
>
> s = btf__str_by_offset(btf, t->name_off);
> - if (str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX)) {
> - description = s + sizeof(TEST_TAG_DESCRIPTION_PFX) - 1;
> + if ((val = str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX))) {
> + description = val;
> } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
> spec->priv.expect_failure = true;
> spec->mode_mask |= PRIV;
> @@ -530,29 +534,24 @@ static int parse_test_spec(struct test_loader *tester,
> if (err)
> goto cleanup;
> spec->mode_mask |= UNPRIV;
> - } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX)) {
> - val = s + sizeof(TEST_TAG_RETVAL_PFX) - 1;
> + } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX))) {
> err = parse_retval(val, &spec->priv.retval, "__retval");
> if (err)
> goto cleanup;
> spec->priv.execute = true;
> spec->mode_mask |= PRIV;
> - } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV)) {
> - val = s + sizeof(TEST_TAG_RETVAL_PFX_UNPRIV) - 1;
> + } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV))) {
> err = parse_retval(val, &spec->unpriv.retval, "__retval_unpriv");
> if (err)
> goto cleanup;
> spec->mode_mask |= UNPRIV;
> spec->unpriv.execute = true;
> has_unpriv_retval = true;
> - } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
> - val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1;
> + } else if ((val = str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX))) {
> err = parse_int(val, &spec->log_level, "test log level");
> if (err)
> goto cleanup;
> - } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) {
> - val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1;
> -
> + } else if ((val = str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX))) {
> clear = val[0] == '!';
> if (clear)
> val++;
> @@ -577,8 +576,7 @@ static int parse_test_spec(struct test_loader *tester,
> goto cleanup;
> update_flags(&spec->prog_flags, flags, clear);
> }
> - } else if (str_has_pfx(s, TEST_TAG_ARCH)) {
> - val = s + sizeof(TEST_TAG_ARCH) - 1;
> + } else if ((val = str_has_pfx(s, TEST_TAG_ARCH))) {
> if (strcmp(val, "X86_64") == 0) {
> arch = ARCH_X86_64;
> } else if (strcmp(val, "ARM64") == 0) {
> @@ -596,16 +594,14 @@ static int parse_test_spec(struct test_loader *tester,
> collect_jit = get_current_arch() == arch;
> unpriv_jit_on_next_line = true;
> jit_on_next_line = true;
> - } else if (str_has_pfx(s, TEST_BTF_PATH)) {
> - spec->btf_custom_path = s + sizeof(TEST_BTF_PATH) - 1;
> - } else if (str_has_pfx(s, TEST_TAG_CAPS_UNPRIV)) {
> - val = s + sizeof(TEST_TAG_CAPS_UNPRIV) - 1;
> + } else if ((val = str_has_pfx(s, TEST_BTF_PATH))) {
> + spec->btf_custom_path = val;
> + } else if ((val = str_has_pfx(s, TEST_TAG_CAPS_UNPRIV))) {
> err = parse_caps(val, &spec->unpriv.caps, "test caps");
> if (err)
> goto cleanup;
> spec->mode_mask |= UNPRIV;
> - } else if (str_has_pfx(s, TEST_TAG_LOAD_MODE_PFX)) {
> - val = s + sizeof(TEST_TAG_LOAD_MODE_PFX) - 1;
> + } else if ((val = str_has_pfx(s, TEST_TAG_LOAD_MODE_PFX))) {
> if (strcmp(val, "jited") == 0) {
> load_mask = JITED;
> } else if (strcmp(val, "no_jited") == 0) {
> @@ -635,12 +631,11 @@ static int parse_test_spec(struct test_loader *tester,
> &spec->unpriv.stdout);
> if (err)
> goto cleanup;
> - } else if (str_has_pfx(s, TEST_TAG_LINEAR_SIZE)) {
> + } else if ((val = str_has_pfx(s, TEST_TAG_LINEAR_SIZE))) {
> switch (bpf_program__type(prog)) {
> case BPF_PROG_TYPE_SCHED_ACT:
> case BPF_PROG_TYPE_SCHED_CLS:
> case BPF_PROG_TYPE_CGROUP_SKB:
> - val = s + sizeof(TEST_TAG_LINEAR_SIZE) - 1;
> err = parse_int(val, &spec->linear_sz, "test linear size");
> if (err)
> goto cleanup;
>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix
2026-03-31 12:07 ` Mykyta Yatsenko
@ 2026-03-31 17:52 ` Eduard Zingerman
0 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 17:52 UTC (permalink / raw)
To: Mykyta Yatsenko, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Ihor Solodrai
On Tue, 2026-03-31 at 13:07 +0100, Mykyta Yatsenko wrote:
> On 3/31/26 1:59 AM, Eduard Zingerman wrote:
> > Change str_has_pfx() to return a pointer to the first character after
> > the prefix, thus eliminating the repetitive (s + sizeof(PFX) - 1)
> > patterns.
> >
> > Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> > tools/testing/selftests/bpf/test_loader.c | 51 ++++++++++++++-----------------
> > 1 file changed, 23 insertions(+), 28 deletions(-)
> >
> > diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
> > index 338c035c36884c02ac57cd17110122c10b4858e4..50ca1b6ec8150efe2cb280667af9ac4972c28657 100644
> > --- a/tools/testing/selftests/bpf/test_loader.c
> > +++ b/tools/testing/selftests/bpf/test_loader.c
> > @@ -11,8 +11,12 @@
> > #include "cap_helpers.h"
> > #include "jit_disasm_helpers.h"
> >
> > -#define str_has_pfx(str, pfx) \
> > - (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
> > +static inline const char *str_has_pfx(const char *str, const char *pfx)
> > +{
> > + size_t len = strlen(pfx);
> > +
> > + return strncmp(str, pfx, len) == 0 ? str + len : NULL;
> > +}
> >
> > #define TEST_LOADER_LOG_BUF_SZ 2097152
> >
> > @@ -161,21 +165,21 @@ static void free_test_spec(struct test_spec *spec)
> > static int compile_regex(const char *pattern, regex_t *regex)
> > {
> > char err_buf[256], buf[256] = {}, *ptr, *buf_end;
> > - const char *original_pattern = pattern;
> > + const char *original_pattern = pattern, *m;
>
> super nit: what does m stand for? Something like `next` would do better,
> wouldn't it?
'm' for 'match' :)
> Overall refactoring looks correct, all callsites of the str_has_pfx()
> are modified, except one in parse_int(), but it's correct anyways.
>
> Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
Thx
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags
2026-03-31 0:59 [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
2026-03-31 0:59 ` [PATCH bpf-next v2 1/4] selftests/bpf: fix __jited_unpriv tag name Eduard Zingerman
2026-03-31 0:59 ` [PATCH bpf-next v2 2/4] selftests/bpf: make str_has_pfx return pointer past the prefix Eduard Zingerman
@ 2026-03-31 0:59 ` Eduard Zingerman
2026-03-31 2:38 ` bot+bpf-ci
2026-03-31 0:59 ` [PATCH bpf-next v2 4/4] selftests/bpf: inline TEST_TAG constants in test_loader.c Eduard Zingerman
2026-03-31 13:03 ` [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Puranjay Mohan
4 siblings, 1 reply; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 0:59 UTC (permalink / raw)
To: bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Eduard Zingerman, Cupertino Miranda
Impose global ordering for all decl tags used by test_loader.c based
tests (__success, __failure, __msg, etc):
- change every tag to expand as
__attribute__((btf_decl_tag("comment:" XSTR(__COUNTER__) ...)))
- change parse_test_spec() to collect all decl tags before
processing and sort them using strverscmp().
The ordering is necessary for gcc-bpf.
Neither GCC nor the C standard defines the order in which function
attributes are consumed. While Clang tends to preserve definition order,
GCC may process them out of sequence. This inconsistency causes BPF
tests with multiple __msg entries to fail when compiled with GCC.
Signed-off-by: Cupertino Miranda <cupertino.miranda@oracle.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/progs/bpf_misc.h | 60 +++++-----
tools/testing/selftests/bpf/test_loader.c | 167 +++++++++++++++------------
2 files changed, 124 insertions(+), 103 deletions(-)
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 52cf9f3cccd0ccd8034b9786d787e53992a4a6d8..32e06c575fbe1f36264c8965cbd84e4432a434d8 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -130,39 +130,41 @@
* __linear_size Specify the size of the linear area of non-linear skbs, or
* 0 for linear skbs.
*/
-#define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg)))
-#define __not_msg(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg=" XSTR(__COUNTER__) "=" msg)))
-#define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" XSTR(__COUNTER__) "=" msg)))
-#define __jited(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg)))
-#define __failure __attribute__((btf_decl_tag("comment:test_expect_failure")))
-#define __success __attribute__((btf_decl_tag("comment:test_expect_success")))
-#define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc)))
-#define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv")))
-#define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv")))
-#define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
-#define __flag(flag) __attribute__((btf_decl_tag("comment:test_prog_flags="#flag)))
-#define __retval(val) __attribute__((btf_decl_tag("comment:test_retval="XSTR(val))))
-#define __retval_unpriv(val) __attribute__((btf_decl_tag("comment:test_retval_unpriv="XSTR(val))))
-#define __auxiliary __attribute__((btf_decl_tag("comment:test_auxiliary")))
-#define __auxiliary_unpriv __attribute__((btf_decl_tag("comment:test_auxiliary_unpriv")))
-#define __btf_path(path) __attribute__((btf_decl_tag("comment:test_btf_path=" path)))
-#define __arch(arch) __attribute__((btf_decl_tag("comment:test_arch=" arch)))
+#define __test_tag(tag) __attribute__((btf_decl_tag("comment:" XSTR(__COUNTER__) ":" tag)))
+
+#define __msg(msg) __test_tag("test_expect_msg=" msg)
+#define __not_msg(msg) __test_tag("test_expect_not_msg=" msg)
+#define __xlated(msg) __test_tag("test_expect_xlated=" msg)
+#define __jited(msg) __test_tag("test_jited=" msg)
+#define __failure __test_tag("test_expect_failure")
+#define __success __test_tag("test_expect_success")
+#define __description(desc) __test_tag("test_description=" desc)
+#define __msg_unpriv(msg) __test_tag("test_expect_msg_unpriv=" msg)
+#define __not_msg_unpriv(msg) __test_tag("test_expect_not_msg_unpriv=" msg)
+#define __xlated_unpriv(msg) __test_tag("test_expect_xlated_unpriv=" msg)
+#define __jited_unpriv(msg) __test_tag("test_jited_unpriv=" msg)
+#define __failure_unpriv __test_tag("test_expect_failure_unpriv")
+#define __success_unpriv __test_tag("test_expect_success_unpriv")
+#define __log_level(lvl) __test_tag("test_log_level=" #lvl)
+#define __flag(flag) __test_tag("test_prog_flags=" #flag)
+#define __retval(val) __test_tag("test_retval=" XSTR(val))
+#define __retval_unpriv(val) __test_tag("test_retval_unpriv=" XSTR(val))
+#define __auxiliary __test_tag("test_auxiliary")
+#define __auxiliary_unpriv __test_tag("test_auxiliary_unpriv")
+#define __btf_path(path) __test_tag("test_btf_path=" path)
+#define __arch(arch) __test_tag("test_arch=" arch)
#define __arch_x86_64 __arch("X86_64")
#define __arch_arm64 __arch("ARM64")
#define __arch_riscv64 __arch("RISCV64")
#define __arch_s390x __arch("s390x")
-#define __caps_unpriv(caps) __attribute__((btf_decl_tag("comment:test_caps_unpriv=" EXPAND_QUOTE(caps))))
-#define __load_if_JITed() __attribute__((btf_decl_tag("comment:load_mode=jited")))
-#define __load_if_no_JITed() __attribute__((btf_decl_tag("comment:load_mode=no_jited")))
-#define __stderr(msg) __attribute__((btf_decl_tag("comment:test_expect_stderr=" XSTR(__COUNTER__) "=" msg)))
-#define __stderr_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_stderr_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __stdout(msg) __attribute__((btf_decl_tag("comment:test_expect_stdout=" XSTR(__COUNTER__) "=" msg)))
-#define __stdout_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_stdout_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __linear_size(sz) __attribute__((btf_decl_tag("comment:test_linear_size=" XSTR(sz))))
+#define __caps_unpriv(caps) __test_tag("test_caps_unpriv=" EXPAND_QUOTE(caps))
+#define __load_if_JITed() __test_tag("load_mode=jited")
+#define __load_if_no_JITed() __test_tag("load_mode=no_jited")
+#define __stderr(msg) __test_tag("test_expect_stderr=" msg)
+#define __stderr_unpriv(msg) __test_tag("test_expect_stderr_unpriv=" msg)
+#define __stdout(msg) __test_tag("test_expect_stdout=" msg)
+#define __stdout_unpriv(msg) __test_tag("test_expect_stdout_unpriv=" msg)
+#define __linear_size(sz) __test_tag("test_linear_size=" XSTR(sz))
/* Define common capabilities tested using __caps_unpriv */
#define CAP_NET_ADMIN 12
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 50ca1b6ec8150efe2cb280667af9ac4972c28657..3f784cc76f8f532b1c110ae3b784cd8ec1ebcf9b 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
#include <linux/capability.h>
+#include <linux/err.h>
#include <stdlib.h>
#include <test_progs.h>
#include <bpf/btf.h>
@@ -20,34 +21,34 @@ static inline const char *str_has_pfx(const char *str, const char *pfx)
#define TEST_LOADER_LOG_BUF_SZ 2097152
-#define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure"
-#define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success"
-#define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg="
-#define TEST_TAG_EXPECT_NOT_MSG_PFX "comment:test_expect_not_msg="
-#define TEST_TAG_EXPECT_XLATED_PFX "comment:test_expect_xlated="
-#define TEST_TAG_EXPECT_FAILURE_UNPRIV "comment:test_expect_failure_unpriv"
-#define TEST_TAG_EXPECT_SUCCESS_UNPRIV "comment:test_expect_success_unpriv"
-#define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "comment:test_expect_msg_unpriv="
-#define TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV "comment:test_expect_not_msg_unpriv="
-#define TEST_TAG_EXPECT_XLATED_PFX_UNPRIV "comment:test_expect_xlated_unpriv="
-#define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level="
-#define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags="
-#define TEST_TAG_DESCRIPTION_PFX "comment:test_description="
-#define TEST_TAG_RETVAL_PFX "comment:test_retval="
-#define TEST_TAG_RETVAL_PFX_UNPRIV "comment:test_retval_unpriv="
-#define TEST_TAG_AUXILIARY "comment:test_auxiliary"
-#define TEST_TAG_AUXILIARY_UNPRIV "comment:test_auxiliary_unpriv"
-#define TEST_BTF_PATH "comment:test_btf_path="
-#define TEST_TAG_ARCH "comment:test_arch="
-#define TEST_TAG_JITED_PFX "comment:test_jited="
-#define TEST_TAG_JITED_PFX_UNPRIV "comment:test_jited_unpriv="
-#define TEST_TAG_CAPS_UNPRIV "comment:test_caps_unpriv="
-#define TEST_TAG_LOAD_MODE_PFX "comment:load_mode="
-#define TEST_TAG_EXPECT_STDERR_PFX "comment:test_expect_stderr="
-#define TEST_TAG_EXPECT_STDERR_PFX_UNPRIV "comment:test_expect_stderr_unpriv="
-#define TEST_TAG_EXPECT_STDOUT_PFX "comment:test_expect_stdout="
-#define TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV "comment:test_expect_stdout_unpriv="
-#define TEST_TAG_LINEAR_SIZE "comment:test_linear_size="
+#define TEST_TAG_EXPECT_FAILURE "test_expect_failure"
+#define TEST_TAG_EXPECT_SUCCESS "test_expect_success"
+#define TEST_TAG_EXPECT_MSG_PFX "test_expect_msg="
+#define TEST_TAG_EXPECT_NOT_MSG_PFX "test_expect_not_msg="
+#define TEST_TAG_EXPECT_XLATED_PFX "test_expect_xlated="
+#define TEST_TAG_EXPECT_FAILURE_UNPRIV "test_expect_failure_unpriv"
+#define TEST_TAG_EXPECT_SUCCESS_UNPRIV "test_expect_success_unpriv"
+#define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "test_expect_msg_unpriv="
+#define TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV "test_expect_not_msg_unpriv="
+#define TEST_TAG_EXPECT_XLATED_PFX_UNPRIV "test_expect_xlated_unpriv="
+#define TEST_TAG_LOG_LEVEL_PFX "test_log_level="
+#define TEST_TAG_PROG_FLAGS_PFX "test_prog_flags="
+#define TEST_TAG_DESCRIPTION_PFX "test_description="
+#define TEST_TAG_RETVAL_PFX "test_retval="
+#define TEST_TAG_RETVAL_PFX_UNPRIV "test_retval_unpriv="
+#define TEST_TAG_AUXILIARY "test_auxiliary"
+#define TEST_TAG_AUXILIARY_UNPRIV "test_auxiliary_unpriv"
+#define TEST_BTF_PATH "test_btf_path="
+#define TEST_TAG_ARCH "test_arch="
+#define TEST_TAG_JITED_PFX "test_jited="
+#define TEST_TAG_JITED_PFX_UNPRIV "test_jited_unpriv="
+#define TEST_TAG_CAPS_UNPRIV "test_caps_unpriv="
+#define TEST_TAG_LOAD_MODE_PFX "load_mode="
+#define TEST_TAG_EXPECT_STDERR_PFX "test_expect_stderr="
+#define TEST_TAG_EXPECT_STDERR_PFX_UNPRIV "test_expect_stderr_unpriv="
+#define TEST_TAG_EXPECT_STDOUT_PFX "test_expect_stdout="
+#define TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV "test_expect_stdout_unpriv="
+#define TEST_TAG_LINEAR_SIZE "test_linear_size="
/* Warning: duplicated in bpf_misc.h */
#define POINTER_VALUE 0xbadcafe
@@ -347,33 +348,49 @@ static void update_flags(int *flags, int flag, bool clear)
*flags |= flag;
}
-/* Matches a string of form '<pfx>[^=]=.*' and returns it's suffix.
- * Used to parse btf_decl_tag values.
- * Such values require unique prefix because compiler does not add
- * same __attribute__((btf_decl_tag(...))) twice.
- * Test suite uses two-component tags for such cases:
- *
- * <pfx> __COUNTER__ '='
- *
- * For example, two consecutive __msg tags '__msg("foo") __msg("foo")'
- * would be encoded as:
- *
- * [18] DECL_TAG 'comment:test_expect_msg=0=foo' type_id=15 component_idx=-1
- * [19] DECL_TAG 'comment:test_expect_msg=1=foo' type_id=15 component_idx=-1
- *
- * And the purpose of this function is to extract 'foo' from the above.
- */
-static const char *skip_dynamic_pfx(const char *s, const char *pfx)
+static const char *skip_decl_tag_pfx(const char *s)
{
- const char *msg;
+ int n = 0;
- if (strncmp(s, pfx, strlen(pfx)) != 0)
+ if (sscanf(s, "comment:%*d:%n", &n) < 0 || !n)
return NULL;
- msg = s + strlen(pfx);
- msg = strchr(msg, '=');
- if (!msg)
- return NULL;
- return msg + 1;
+ return s + n;
+}
+
+static int compare_decl_tags(const void *a, const void *b)
+{
+ return strverscmp(*(const char **)a, *(const char **)b);
+}
+
+/*
+ * Compilers don't guarantee order in which BTF attributes would be generated,
+ * while order is important for test tags like __msg.
+ * Each test tag has the following prefix: "comment:" __COUNTER__,
+ * when sorted using strverscmp this gives same order as in the original C code.
+ */
+static const char **collect_decl_tags(struct btf *btf, int id, int *cnt)
+{
+ const char **tmp, **tags = NULL;
+ const struct btf_type *t;
+ int i;
+
+ *cnt = 0;
+ for (i = 1; i < btf__type_cnt(btf); i++) {
+ t = btf__type_by_id(btf, i);
+ if (!btf_is_decl_tag(t) || t->type != id || btf_decl_tag(t)->component_idx != -1)
+ continue;
+ tmp = realloc(tags, (*cnt + 1) * sizeof(*tags));
+ if (!tmp) {
+ free(tmp);
+ return ERR_PTR(-ENOMEM);
+ }
+ tags = tmp;
+ tags[(*cnt)++] = btf__str_by_offset(btf, t->name_off);
+ }
+
+ if (*cnt)
+ qsort(tags, *cnt, sizeof(*tags), compare_decl_tags);
+ return tags;
}
enum arch {
@@ -419,7 +436,9 @@ static int parse_test_spec(struct test_loader *tester,
bool stdout_on_next_line = true;
bool unpriv_stdout_on_next_line = true;
bool collect_jit = false;
- int func_id, i, err = 0;
+ const char **tags = NULL;
+ int func_id, i, nr_tags;
+ int err = 0;
u32 arch_mask = 0;
u32 load_mask = 0;
struct btf *btf;
@@ -442,20 +461,18 @@ static int parse_test_spec(struct test_loader *tester,
return -EINVAL;
}
- for (i = 1; i < btf__type_cnt(btf); i++) {
+ tags = collect_decl_tags(btf, func_id, &nr_tags);
+ if (IS_ERR(tags))
+ return PTR_ERR(tags);
+
+ for (i = 0; i < nr_tags; i++) {
const char *s, *val, *msg;
- const struct btf_type *t;
bool clear;
int flags;
- t = btf__type_by_id(btf, i);
- if (!btf_is_decl_tag(t))
+ s = skip_decl_tag_pfx(tags[i]);
+ if (!s)
continue;
-
- if (t->type != func_id || btf_decl_tag(t)->component_idx != -1)
- continue;
-
- s = btf__str_by_offset(btf, t->name_off);
if ((val = str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX))) {
description = val;
} else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
@@ -478,27 +495,27 @@ static int parse_test_spec(struct test_loader *tester,
} else if (strcmp(s, TEST_TAG_AUXILIARY_UNPRIV) == 0) {
spec->auxiliary = true;
spec->mode_mask |= UNPRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX))) {
err = push_msg(msg, false, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX))) {
err = push_msg(msg, true, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV))) {
err = push_msg(msg, false, &spec->unpriv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV))) {
err = push_msg(msg, true, &spec->unpriv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_JITED_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_JITED_PFX))) {
if (arch_mask == 0) {
PRINT_FAIL("__jited used before __arch_*");
goto cleanup;
@@ -510,7 +527,7 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
spec->mode_mask |= PRIV;
}
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_JITED_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_JITED_PFX_UNPRIV))) {
if (arch_mask == 0) {
PRINT_FAIL("__unpriv_jited used before __arch_*");
goto cleanup;
@@ -522,13 +539,13 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
spec->mode_mask |= UNPRIV;
}
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_XLATED_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX))) {
err = push_disasm_msg(msg, &xlated_on_next_line,
&spec->priv.expect_xlated);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV))) {
err = push_disasm_msg(msg, &unpriv_xlated_on_next_line,
&spec->unpriv.expect_xlated);
if (err)
@@ -611,22 +628,22 @@ static int parse_test_spec(struct test_loader *tester,
err = -EINVAL;
goto cleanup;
}
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDERR_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDERR_PFX))) {
err = push_disasm_msg(msg, &stderr_on_next_line,
&spec->priv.stderr);
if (err)
goto cleanup;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDERR_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDERR_PFX_UNPRIV))) {
err = push_disasm_msg(msg, &unpriv_stderr_on_next_line,
&spec->unpriv.stderr);
if (err)
goto cleanup;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX))) {
err = push_disasm_msg(msg, &stdout_on_next_line,
&spec->priv.stdout);
if (err)
goto cleanup;
- } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV))) {
err = push_disasm_msg(msg, &unpriv_stdout_on_next_line,
&spec->unpriv.stdout);
if (err)
@@ -706,9 +723,11 @@ static int parse_test_spec(struct test_loader *tester,
spec->valid = true;
+ free(tags);
return 0;
cleanup:
+ free(tags);
free_test_spec(spec);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags
2026-03-31 0:59 ` [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
@ 2026-03-31 2:38 ` bot+bpf-ci
2026-03-31 13:02 ` Puranjay Mohan
0 siblings, 1 reply; 11+ messages in thread
From: bot+bpf-ci @ 2026-03-31 2:38 UTC (permalink / raw)
To: eddyz87, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song, eddyz87,
cupertino.miranda, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1216 bytes --]
> diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
> index 50ca1b6ec8150..3f784cc76f8f5 100644
> --- a/tools/testing/selftests/bpf/test_loader.c
> +++ b/tools/testing/selftests/bpf/test_loader.c
[ ... ]
> +static const char **collect_decl_tags(struct btf *btf, int id, int *cnt)
> +{
> + const char **tmp, **tags = NULL;
> + const struct btf_type *t;
> + int i;
> +
> + *cnt = 0;
> + for (i = 1; i < btf__type_cnt(btf); i++) {
> + t = btf__type_by_id(btf, i);
> + if (!btf_is_decl_tag(t) || t->type != id || btf_decl_tag(t)->component_idx != -1)
> + continue;
> + tmp = realloc(tags, (*cnt + 1) * sizeof(*tags));
> + if (!tmp) {
> + free(tmp);
> + return ERR_PTR(-ENOMEM);
> + }
Should free(tmp) be free(tags) here? When realloc fails, tmp is NULL,
so free(tmp) is a no-op. The previously allocated tags array would be
leaked.
> + tags = tmp;
> + tags[(*cnt)++] = btf__str_by_offset(btf, t->name_off);
> + }
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/23775718736
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags
2026-03-31 2:38 ` bot+bpf-ci
@ 2026-03-31 13:02 ` Puranjay Mohan
2026-03-31 17:52 ` Eduard Zingerman
0 siblings, 1 reply; 11+ messages in thread
From: Puranjay Mohan @ 2026-03-31 13:02 UTC (permalink / raw)
To: bot+bpf-ci, eddyz87, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song, eddyz87,
cupertino.miranda, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai, Puranjay Mohan
bot+bpf-ci@kernel.org writes:
>> diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
>> index 50ca1b6ec8150..3f784cc76f8f5 100644
>> --- a/tools/testing/selftests/bpf/test_loader.c
>> +++ b/tools/testing/selftests/bpf/test_loader.c
>
> [ ... ]
>
>> +static const char **collect_decl_tags(struct btf *btf, int id, int *cnt)
>> +{
>> + const char **tmp, **tags = NULL;
>> + const struct btf_type *t;
>> + int i;
>> +
>> + *cnt = 0;
>> + for (i = 1; i < btf__type_cnt(btf); i++) {
>> + t = btf__type_by_id(btf, i);
>> + if (!btf_is_decl_tag(t) || t->type != id || btf_decl_tag(t)->component_idx != -1)
>> + continue;
>> + tmp = realloc(tags, (*cnt + 1) * sizeof(*tags));
>> + if (!tmp) {
>> + free(tmp);
>> + return ERR_PTR(-ENOMEM);
>> + }
>
> Should free(tmp) be free(tags) here? When realloc fails, tmp is NULL,
> so free(tmp) is a no-op. The previously allocated tags array would be
> leaked.
>
This is correct, realloc() will return NULL on failure, we should do free(tags)
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags
2026-03-31 13:02 ` Puranjay Mohan
@ 2026-03-31 17:52 ` Eduard Zingerman
0 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 17:52 UTC (permalink / raw)
To: Puranjay Mohan, bot+bpf-ci, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
cupertino.miranda, martin.lau, clm, ihor.solodrai, Puranjay Mohan
On Tue, 2026-03-31 at 14:02 +0100, Puranjay Mohan wrote:
> bot+bpf-ci@kernel.org writes:
>
> > > diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
> > > index 50ca1b6ec8150..3f784cc76f8f5 100644
> > > --- a/tools/testing/selftests/bpf/test_loader.c
> > > +++ b/tools/testing/selftests/bpf/test_loader.c
> >
> > [ ... ]
> >
> > > +static const char **collect_decl_tags(struct btf *btf, int id, int *cnt)
> > > +{
> > > + const char **tmp, **tags = NULL;
> > > + const struct btf_type *t;
> > > + int i;
> > > +
> > > + *cnt = 0;
> > > + for (i = 1; i < btf__type_cnt(btf); i++) {
> > > + t = btf__type_by_id(btf, i);
> > > + if (!btf_is_decl_tag(t) || t->type != id || btf_decl_tag(t)->component_idx != -1)
> > > + continue;
> > > + tmp = realloc(tags, (*cnt + 1) * sizeof(*tags));
> > > + if (!tmp) {
> > > + free(tmp);
> > > + return ERR_PTR(-ENOMEM);
> > > + }
> >
> > Should free(tmp) be free(tags) here? When realloc fails, tmp is NULL,
> > so free(tmp) is a no-op. The previously allocated tags array would be
> > leaked.
> >
>
> This is correct, realloc() will return NULL on failure, we should do free(tags)
Yeap, need to send a v3.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf-next v2 4/4] selftests/bpf: inline TEST_TAG constants in test_loader.c
2026-03-31 0:59 [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
` (2 preceding siblings ...)
2026-03-31 0:59 ` [PATCH bpf-next v2 3/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
@ 2026-03-31 0:59 ` Eduard Zingerman
2026-03-31 13:03 ` [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Puranjay Mohan
4 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2026-03-31 0:59 UTC (permalink / raw)
To: bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Eduard Zingerman, Ihor Solodrai
After str_has_pfx() refactoring each TEST_TAG_* / TEST_BTF_PATH
constant is used exactly once. Since constant definitions are not
shared between BPF-side bpf_misc.h and userspace side test_loader.c,
there is no need in the additional redirection layer.
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/test_loader.c | 84 +++++++++++--------------------
1 file changed, 28 insertions(+), 56 deletions(-)
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 3f784cc76f8f532b1c110ae3b784cd8ec1ebcf9b..f55410e478ce1f4e0352cb2a0c05a493178ec756 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -21,34 +21,6 @@ static inline const char *str_has_pfx(const char *str, const char *pfx)
#define TEST_LOADER_LOG_BUF_SZ 2097152
-#define TEST_TAG_EXPECT_FAILURE "test_expect_failure"
-#define TEST_TAG_EXPECT_SUCCESS "test_expect_success"
-#define TEST_TAG_EXPECT_MSG_PFX "test_expect_msg="
-#define TEST_TAG_EXPECT_NOT_MSG_PFX "test_expect_not_msg="
-#define TEST_TAG_EXPECT_XLATED_PFX "test_expect_xlated="
-#define TEST_TAG_EXPECT_FAILURE_UNPRIV "test_expect_failure_unpriv"
-#define TEST_TAG_EXPECT_SUCCESS_UNPRIV "test_expect_success_unpriv"
-#define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "test_expect_msg_unpriv="
-#define TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV "test_expect_not_msg_unpriv="
-#define TEST_TAG_EXPECT_XLATED_PFX_UNPRIV "test_expect_xlated_unpriv="
-#define TEST_TAG_LOG_LEVEL_PFX "test_log_level="
-#define TEST_TAG_PROG_FLAGS_PFX "test_prog_flags="
-#define TEST_TAG_DESCRIPTION_PFX "test_description="
-#define TEST_TAG_RETVAL_PFX "test_retval="
-#define TEST_TAG_RETVAL_PFX_UNPRIV "test_retval_unpriv="
-#define TEST_TAG_AUXILIARY "test_auxiliary"
-#define TEST_TAG_AUXILIARY_UNPRIV "test_auxiliary_unpriv"
-#define TEST_BTF_PATH "test_btf_path="
-#define TEST_TAG_ARCH "test_arch="
-#define TEST_TAG_JITED_PFX "test_jited="
-#define TEST_TAG_JITED_PFX_UNPRIV "test_jited_unpriv="
-#define TEST_TAG_CAPS_UNPRIV "test_caps_unpriv="
-#define TEST_TAG_LOAD_MODE_PFX "load_mode="
-#define TEST_TAG_EXPECT_STDERR_PFX "test_expect_stderr="
-#define TEST_TAG_EXPECT_STDERR_PFX_UNPRIV "test_expect_stderr_unpriv="
-#define TEST_TAG_EXPECT_STDOUT_PFX "test_expect_stdout="
-#define TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV "test_expect_stdout_unpriv="
-#define TEST_TAG_LINEAR_SIZE "test_linear_size="
/* Warning: duplicated in bpf_misc.h */
#define POINTER_VALUE 0xbadcafe
@@ -473,49 +445,49 @@ static int parse_test_spec(struct test_loader *tester,
s = skip_decl_tag_pfx(tags[i]);
if (!s)
continue;
- if ((val = str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX))) {
+ if ((val = str_has_pfx(s, "test_description="))) {
description = val;
- } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
+ } else if (strcmp(s, "test_expect_failure") == 0) {
spec->priv.expect_failure = true;
spec->mode_mask |= PRIV;
- } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) {
+ } else if (strcmp(s, "test_expect_success") == 0) {
spec->priv.expect_failure = false;
spec->mode_mask |= PRIV;
- } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE_UNPRIV) == 0) {
+ } else if (strcmp(s, "test_expect_failure_unpriv") == 0) {
spec->unpriv.expect_failure = true;
spec->mode_mask |= UNPRIV;
has_unpriv_result = true;
- } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS_UNPRIV) == 0) {
+ } else if (strcmp(s, "test_expect_success_unpriv") == 0) {
spec->unpriv.expect_failure = false;
spec->mode_mask |= UNPRIV;
has_unpriv_result = true;
- } else if (strcmp(s, TEST_TAG_AUXILIARY) == 0) {
+ } else if (strcmp(s, "test_auxiliary") == 0) {
spec->auxiliary = true;
spec->mode_mask |= PRIV;
- } else if (strcmp(s, TEST_TAG_AUXILIARY_UNPRIV) == 0) {
+ } else if (strcmp(s, "test_auxiliary_unpriv") == 0) {
spec->auxiliary = true;
spec->mode_mask |= UNPRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_msg="))) {
err = push_msg(msg, false, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_not_msg="))) {
err = push_msg(msg, true, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_msg_unpriv="))) {
err = push_msg(msg, false, &spec->unpriv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_not_msg_unpriv="))) {
err = push_msg(msg, true, &spec->unpriv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_JITED_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_jited="))) {
if (arch_mask == 0) {
PRINT_FAIL("__jited used before __arch_*");
goto cleanup;
@@ -527,7 +499,7 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
spec->mode_mask |= PRIV;
}
- } else if ((msg = str_has_pfx(s, TEST_TAG_JITED_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_jited_unpriv="))) {
if (arch_mask == 0) {
PRINT_FAIL("__unpriv_jited used before __arch_*");
goto cleanup;
@@ -539,36 +511,36 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
spec->mode_mask |= UNPRIV;
}
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_xlated="))) {
err = push_disasm_msg(msg, &xlated_on_next_line,
&spec->priv.expect_xlated);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_xlated_unpriv="))) {
err = push_disasm_msg(msg, &unpriv_xlated_on_next_line,
&spec->unpriv.expect_xlated);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX))) {
+ } else if ((val = str_has_pfx(s, "test_retval="))) {
err = parse_retval(val, &spec->priv.retval, "__retval");
if (err)
goto cleanup;
spec->priv.execute = true;
spec->mode_mask |= PRIV;
- } else if ((val = str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV))) {
+ } else if ((val = str_has_pfx(s, "test_retval_unpriv="))) {
err = parse_retval(val, &spec->unpriv.retval, "__retval_unpriv");
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
spec->unpriv.execute = true;
has_unpriv_retval = true;
- } else if ((val = str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX))) {
+ } else if ((val = str_has_pfx(s, "test_log_level="))) {
err = parse_int(val, &spec->log_level, "test log level");
if (err)
goto cleanup;
- } else if ((val = str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX))) {
+ } else if ((val = str_has_pfx(s, "test_prog_flags="))) {
clear = val[0] == '!';
if (clear)
val++;
@@ -593,7 +565,7 @@ static int parse_test_spec(struct test_loader *tester,
goto cleanup;
update_flags(&spec->prog_flags, flags, clear);
}
- } else if ((val = str_has_pfx(s, TEST_TAG_ARCH))) {
+ } else if ((val = str_has_pfx(s, "test_arch="))) {
if (strcmp(val, "X86_64") == 0) {
arch = ARCH_X86_64;
} else if (strcmp(val, "ARM64") == 0) {
@@ -611,14 +583,14 @@ static int parse_test_spec(struct test_loader *tester,
collect_jit = get_current_arch() == arch;
unpriv_jit_on_next_line = true;
jit_on_next_line = true;
- } else if ((val = str_has_pfx(s, TEST_BTF_PATH))) {
+ } else if ((val = str_has_pfx(s, "test_btf_path="))) {
spec->btf_custom_path = val;
- } else if ((val = str_has_pfx(s, TEST_TAG_CAPS_UNPRIV))) {
+ } else if ((val = str_has_pfx(s, "test_caps_unpriv="))) {
err = parse_caps(val, &spec->unpriv.caps, "test caps");
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
- } else if ((val = str_has_pfx(s, TEST_TAG_LOAD_MODE_PFX))) {
+ } else if ((val = str_has_pfx(s, "load_mode="))) {
if (strcmp(val, "jited") == 0) {
load_mask = JITED;
} else if (strcmp(val, "no_jited") == 0) {
@@ -628,27 +600,27 @@ static int parse_test_spec(struct test_loader *tester,
err = -EINVAL;
goto cleanup;
}
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDERR_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_stderr="))) {
err = push_disasm_msg(msg, &stderr_on_next_line,
&spec->priv.stderr);
if (err)
goto cleanup;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDERR_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_stderr_unpriv="))) {
err = push_disasm_msg(msg, &unpriv_stderr_on_next_line,
&spec->unpriv.stderr);
if (err)
goto cleanup;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_stdout="))) {
err = push_disasm_msg(msg, &stdout_on_next_line,
&spec->priv.stdout);
if (err)
goto cleanup;
- } else if ((msg = str_has_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV))) {
+ } else if ((msg = str_has_pfx(s, "test_expect_stdout_unpriv="))) {
err = push_disasm_msg(msg, &unpriv_stdout_on_next_line,
&spec->unpriv.stdout);
if (err)
goto cleanup;
- } else if ((val = str_has_pfx(s, TEST_TAG_LINEAR_SIZE))) {
+ } else if ((val = str_has_pfx(s, "test_linear_size="))) {
switch (bpf_program__type(prog)) {
case BPF_PROG_TYPE_SCHED_ACT:
case BPF_PROG_TYPE_SCHED_CLS:
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags
2026-03-31 0:59 [PATCH bpf-next v2 0/4] selftests/bpf: impose global ordering for test decl_tags Eduard Zingerman
` (3 preceding siblings ...)
2026-03-31 0:59 ` [PATCH bpf-next v2 4/4] selftests/bpf: inline TEST_TAG constants in test_loader.c Eduard Zingerman
@ 2026-03-31 13:03 ` Puranjay Mohan
4 siblings, 0 replies; 11+ messages in thread
From: Puranjay Mohan @ 2026-03-31 13:03 UTC (permalink / raw)
To: Eduard Zingerman, bpf, ast
Cc: andrii, daniel, martin.lau, kernel-team, yonghong.song,
Eduard Zingerman, Puranjay Mohan
Eduard Zingerman <eddyz87@gmail.com> writes:
> Impose global ordering for all decl tags used by test_loader.c based
> tests: __success, __failure, __msg, etc. The tags are now sorted by
> testing framework to be processed in the same order they appear in the
> C source code of the test.
>
> The ordering is necessary for gcc-bpf. Neither GCC nor the C standard
> defines the order in which function attributes are consumed.
> While Clang tends to preserve tags definition order in the output BTF,
> GCC does not. This inconsistency causes BPF tests with multiple __msg
> entries to fail when compiled with GCC.
>
> This is based on a patch [1] from Cupertino Miranda (see patch #3) and
> includes some additional cleanups for test_loader.c decl tags
> declaration and processing (see patches #1, #2, #4).
>
> [1] https://lore.kernel.org/bpf/20260305130035.192080-1-cupertino.miranda@oracle.com/
>
> Changelog:
> v1 -> v2:
> - updated remaining str_has_pfx() usages (Puranjay)
> - removed realloc_or_free() (Andrii)
> - fixed qsort(NULL, ...) usage (Puranjay)
> - skip_decl_tag_pfx() returns NULL if tag does not start from
> "comment:" (Puranjay)
>
> v1: https://lore.kernel.org/bpf/20260326-selftests-global-tags-ordering-v1-0-5dd2ced5d9ad@gmail.com/
> ---
> Eduard Zingerman (4):
> selftests/bpf: fix __jited_unpriv tag name
> selftests/bpf: make str_has_pfx return pointer past the prefix
> selftests/bpf: impose global ordering for test decl_tags
> selftests/bpf: inline TEST_TAG constants in test_loader.c
>
> tools/testing/selftests/bpf/progs/bpf_misc.h | 60 ++++----
> tools/testing/selftests/bpf/test_loader.c | 202 +++++++++++++--------------
> 2 files changed, 125 insertions(+), 137 deletions(-)
> ---
> base-commit: b6b5e0ebd429d66ce37ae5af649a74ea1f041d92
> change-id: 20260326-selftests-global-tags-ordering-8f324323d9c8
This set looks good to me, after changing the free path of realloc():
Reviewed-by: Puranjay Mohan <puranjay@kernel.org>
^ permalink raw reply [flat|nested] 11+ messages in thread