Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: fix to avoid __msg tag de-duplication by clang

__msg, __regex and __xlated tags are based on
__attribute__((btf_decl_tag("..."))) annotations.

Clang de-duplicates such annotations, e.g. the following
two sequences of tags are identical in final BTF:

/* seq A */ /* seq B */
__tag("foo") __tag("foo")
__tag("bar") __tag("bar")
__tag("foo")

Fix this by adding a unique suffix for each tag using __COUNTER__
pre-processor macro. E.g. here is a new definition for __msg:

#define __msg(msg) \
__attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg)))

Using this definition the "seq A" from example above is translated to
BTF as follows:

[..] DECL_TAG 'comment:test_expect_msg=0=foo' type_id=X component_idx=-1
[..] DECL_TAG 'comment:test_expect_msg=1=bar' type_id=X component_idx=-1
[..] DECL_TAG 'comment:test_expect_msg=2=foo' type_id=X component_idx=-1

Surprisingly, this bug affects a single existing test:
verifier_spill_fill/old_stack_misc_vs_cur_ctx_ptr,
where sequence of identical messages was expected in the log.

Fixes: 537c3f66eac1 ("selftests/bpf: add generic BPF program tester-loader")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240820102357.3372779-4-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
f00bb757 d0a29cdb

+48 -22
+9 -6
tools/testing/selftests/bpf/progs/bpf_misc.h
··· 2 2 #ifndef __BPF_MISC_H__ 3 3 #define __BPF_MISC_H__ 4 4 5 + #define XSTR(s) STR(s) 6 + #define STR(s) #s 7 + 5 8 /* This set of attributes controls behavior of the 6 9 * test_loader.c:test_loader__run_subtests(). 7 10 * ··· 71 68 * Several __arch_* annotations could be specified at once. 72 69 * When test case is not run on current arch it is marked as skipped. 73 70 */ 74 - #define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" msg))) 75 - #define __regex(regex) __attribute__((btf_decl_tag("comment:test_expect_regex=" regex))) 76 - #define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" msg))) 71 + #define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg))) 72 + #define __regex(regex) __attribute__((btf_decl_tag("comment:test_expect_regex=" XSTR(__COUNTER__) "=" regex))) 73 + #define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" XSTR(__COUNTER__) "=" msg))) 77 74 #define __failure __attribute__((btf_decl_tag("comment:test_expect_failure"))) 78 75 #define __success __attribute__((btf_decl_tag("comment:test_expect_success"))) 79 76 #define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc))) 80 - #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" msg))) 81 - #define __regex_unpriv(regex) __attribute__((btf_decl_tag("comment:test_expect_regex_unpriv=" regex))) 82 - #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" msg))) 77 + #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) 78 + #define __regex_unpriv(regex) __attribute__((btf_decl_tag("comment:test_expect_regex_unpriv=" XSTR(__COUNTER__) "=" regex))) 79 + #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg))) 83 80 #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv"))) 84 81 #define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv"))) 85 82 #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
+4 -4
tools/testing/selftests/bpf/progs/verifier_spill_fill.c
··· 1213 1213 * - once for path entry - label 2; 1214 1214 * - once for path entry - label 1 - label 2. 1215 1215 */ 1216 - __msg("r1 = *(u64 *)(r10 -8)") 1217 - __msg("exit") 1218 - __msg("r1 = *(u64 *)(r10 -8)") 1219 - __msg("exit") 1216 + __msg("8: (79) r1 = *(u64 *)(r10 -8)") 1217 + __msg("9: (95) exit") 1218 + __msg("from 2 to 7") 1219 + __msg("8: safe") 1220 1220 __msg("processed 11 insns") 1221 1221 __flag(BPF_F_TEST_STATE_FREQ) 1222 1222 __naked void old_stack_misc_vs_cur_ctx_ptr(void)
+35 -12
tools/testing/selftests/bpf/test_loader.c
··· 215 215 *flags |= flag; 216 216 } 217 217 218 + /* Matches a string of form '<pfx>[^=]=.*' and returns it's suffix. 219 + * Used to parse btf_decl_tag values. 220 + * Such values require unique prefix because compiler does not add 221 + * same __attribute__((btf_decl_tag(...))) twice. 222 + * Test suite uses two-component tags for such cases: 223 + * 224 + * <pfx> __COUNTER__ '=' 225 + * 226 + * For example, two consecutive __msg tags '__msg("foo") __msg("foo")' 227 + * would be encoded as: 228 + * 229 + * [18] DECL_TAG 'comment:test_expect_msg=0=foo' type_id=15 component_idx=-1 230 + * [19] DECL_TAG 'comment:test_expect_msg=1=foo' type_id=15 component_idx=-1 231 + * 232 + * And the purpose of this function is to extract 'foo' from the above. 233 + */ 234 + static const char *skip_dynamic_pfx(const char *s, const char *pfx) 235 + { 236 + const char *msg; 237 + 238 + if (strncmp(s, pfx, strlen(pfx)) != 0) 239 + return NULL; 240 + msg = s + strlen(pfx); 241 + msg = strchr(msg, '='); 242 + if (!msg) 243 + return NULL; 244 + return msg + 1; 245 + } 246 + 218 247 enum arch { 219 248 ARCH_X86_64 = 0x1, 220 249 ARCH_ARM64 = 0x2, ··· 319 290 } else if (strcmp(s, TEST_TAG_AUXILIARY_UNPRIV) == 0) { 320 291 spec->auxiliary = true; 321 292 spec->mode_mask |= UNPRIV; 322 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 323 - msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 293 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX))) { 324 294 err = push_msg(msg, NULL, &spec->priv.expect_msgs); 325 295 if (err) 326 296 goto cleanup; 327 297 spec->mode_mask |= PRIV; 328 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV)) { 329 - msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX_UNPRIV) - 1; 298 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV))) { 330 299 err = push_msg(msg, NULL, &spec->unpriv.expect_msgs); 331 300 if (err) 332 301 goto cleanup; 333 302 spec->mode_mask |= UNPRIV; 334 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX)) { 335 - msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX) - 1; 303 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_REGEX_PFX))) { 336 304 err = push_msg(NULL, msg, &spec->priv.expect_msgs); 337 305 if (err) 338 306 goto cleanup; 339 307 spec->mode_mask |= PRIV; 340 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX_UNPRIV)) { 341 - msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX_UNPRIV) - 1; 308 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_REGEX_PFX_UNPRIV))) { 342 309 err = push_msg(NULL, msg, &spec->unpriv.expect_msgs); 343 310 if (err) 344 311 goto cleanup; 345 312 spec->mode_mask |= UNPRIV; 346 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX)) { 347 - msg = s + sizeof(TEST_TAG_EXPECT_XLATED_PFX) - 1; 313 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_XLATED_PFX))) { 348 314 err = push_msg(msg, NULL, &spec->priv.expect_xlated); 349 315 if (err) 350 316 goto cleanup; 351 317 spec->mode_mask |= PRIV; 352 - } else if (str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV)) { 353 - msg = s + sizeof(TEST_TAG_EXPECT_XLATED_PFX_UNPRIV) - 1; 318 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV))) { 354 319 err = push_msg(msg, NULL, &spec->unpriv.expect_xlated); 355 320 if (err) 356 321 goto cleanup;