diff --git a/scripts/format-code b/scripts/format-code old mode 100644 new mode 100755 diff --git a/src/ir/assertions.cpp b/src/ir/assertions.cpp index 9505797b3..ede9d284c 100644 --- a/src/ir/assertions.cpp +++ b/src/ir/assertions.cpp @@ -110,19 +110,13 @@ class AssertExtractor { res.emplace_back(a); } break; - case ArgSingle::Kind::PTR_TO_SOCKET: - res.emplace_back(TypeConstraint{arg.reg, TypeGroup::socket}); - break; - case ArgSingle::Kind::PTR_TO_BTF_ID: - res.emplace_back(TypeConstraint{arg.reg, TypeGroup::btf_id}); - break; + case ArgSingle::Kind::PTR_TO_SOCKET: res.emplace_back(TypeConstraint{arg.reg, TypeGroup::socket}); break; + case ArgSingle::Kind::PTR_TO_BTF_ID: res.emplace_back(TypeConstraint{arg.reg, TypeGroup::btf_id}); break; case ArgSingle::Kind::PTR_TO_ALLOC_MEM: res.emplace_back(TypeConstraint{arg.reg, TypeGroup::alloc_mem}); break; case ArgSingle::Kind::PTR_TO_SPIN_LOCK: - case ArgSingle::Kind::PTR_TO_TIMER: - res.emplace_back(TypeConstraint{arg.reg, TypeGroup::mem}); - break; + case ArgSingle::Kind::PTR_TO_TIMER: res.emplace_back(TypeConstraint{arg.reg, TypeGroup::mem}); break; case ArgSingle::Kind::CONST_SIZE_OR_ZERO: res.emplace_back(TypeConstraint{arg.reg, TypeGroup::number}); res.emplace_back(ValidSize{arg.reg, true}); diff --git a/src/ir/unmarshal.cpp b/src/ir/unmarshal.cpp index 789df1d46..846f98525 100644 --- a/src/ir/unmarshal.cpp +++ b/src/ir/unmarshal.cpp @@ -390,8 +390,8 @@ struct Unmarshaller { } [[nodiscard]] - auto makeLddw(const EbpfInst inst, const int32_t next_imm, const vector& insts, - const Pc pc) const -> Instruction { + auto makeLddw(const EbpfInst inst, const int32_t next_imm, const vector& insts, const Pc pc) const + -> Instruction { if (pc >= insts.size() - 1) { throw InvalidInstruction(pc, "incomplete lddw"); } @@ -502,7 +502,8 @@ struct Unmarshaller { }; const auto return_info = classify_call_return_type(proto.return_type); if (!return_info.has_value()) { - return mark_unsupported(std::string("helper prototype is unavailable on this platform: ") + helper_prototype_name); + return mark_unsupported(std::string("helper prototype is unavailable on this platform: ") + + helper_prototype_name); } res.return_ptr_type = return_info->pointer_type; res.return_nullable = return_info->pointer_nullable; diff --git a/src/test/test_verify.hpp b/src/test/test_verify.hpp index f9bbbd513..376791719 100644 --- a/src/test/test_verify.hpp +++ b/src/test/test_verify.hpp @@ -3,8 +3,6 @@ #pragma once #include -#include -#include #include #include #include @@ -14,7 +12,6 @@ #include "ebpf_verifier.hpp" #include "io/elf_loader.hpp" -#include "linux/gpl/spec_type_descriptors.hpp" namespace verify_test { @@ -68,7 +65,7 @@ inline const char* to_string(VerifyIssueKind kind) noexcept { } template -inline void hash_combine(size_t& seed, const T& value) noexcept { +void hash_combine(size_t& seed, const T& value) noexcept { seed ^= std::hash{}(value) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); } @@ -98,7 +95,7 @@ inline std::vector read_elf_cached(const std::string& path, static std::mutex cache_mutex; static std::unordered_map object_cache; - ElfObjectCacheKey key{ + const ElfObjectCacheKey key{ .path = path, .platform = platform, .verbosity_print_line_info = options.verbosity_opts.print_line_info, @@ -113,8 +110,57 @@ inline std::vector read_elf_cached(const std::string& path, return it->second.get_programs(desired_section, desired_program); } +// Compile-time test name truncation. Catch2's TEST_CASE accepts any const char*, +// so we can pass .data from a constexpr char array instead of a string literal. +// When the name exceeds MAX_LEN, we truncate and append a 4-digit hex hash of the +// full name to preserve uniqueness. +struct BoundedTestName { + static constexpr size_t MAX_LEN = 75; + char data[MAX_LEN + 1]{}; + + template + explicit constexpr BoundedTestName(const char (&str)[N]) { + if constexpr (N - 1 <= MAX_LEN) { + for (size_t i = 0; i < N; ++i) { + data[i] = str[i]; + } + } else { + // FNV-1a hash of full name for a unique suffix. + uint32_t hash = 2166136261u; + for (size_t i = 0; i < N - 1; ++i) { + hash ^= static_cast(str[i]); + hash *= 16777619u; + } + // Format: first (MAX_LEN - 6) chars + "..xxxx" + constexpr size_t prefix_len = MAX_LEN - 6; + for (size_t i = 0; i < prefix_len; ++i) { + data[i] = str[i]; + } + data[prefix_len] = '.'; + data[prefix_len + 1] = '.'; + constexpr char hex[] = "0123456789abcdef"; + data[prefix_len + 2] = hex[(hash >> 12) & 0xf]; + data[prefix_len + 3] = hex[(hash >> 8) & 0xf]; + data[prefix_len + 4] = hex[(hash >> 4) & 0xf]; + data[prefix_len + 5] = hex[hash & 0xf]; + data[MAX_LEN] = '\0'; + } + } +}; + } // namespace verify_test +// BOUNDED_TEST_CASE: like TEST_CASE, but truncates names exceeding MAX_LEN characters. +// Uses __LINE__ to generate a unique constexpr variable name; both expansions of +// PREVAIL_BOUNDED_NAME within one macro invocation share the same __LINE__. +#define PREVAIL_CONCAT_IMPL(a, b) a##b +#define PREVAIL_CONCAT(a, b) PREVAIL_CONCAT_IMPL(a, b) +#define PREVAIL_BOUNDED_NAME PREVAIL_CONCAT(_prevail_btn_, __LINE__) + +#define BOUNDED_TEST_CASE(name_literal, tags) \ + static constexpr verify_test::BoundedTestName PREVAIL_BOUNDED_NAME(name_literal); \ + TEST_CASE(PREVAIL_BOUNDED_NAME.data, tags) + // Verify a program in a section that may have multiple programs in it. #define VERIFY_PROGRAM(dirname, filename, section_name, program_name, _options, platform, should_pass, count) \ do { \ @@ -162,88 +208,90 @@ inline std::vector read_elf_cached(const std::string& path, VERIFY_PROGRAM(dirname, filename, section_name, "", _options, platform, should_pass, 1) #define TEST_SECTION(project, filename, section) \ - TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ } -#define TEST_SECTION_SLOW(project, filename, section) \ - TEST_CASE(project "/" filename " " section, "[verify][samples][slow][" project "]") { \ - VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ +#define TEST_SECTION_SLOW(project, filename, section) \ + BOUNDED_TEST_CASE(project "/" filename " " section, "[verify][samples][slow][" project "]") { \ + VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ } #define TEST_PROGRAM(project, filename, section_name, program_name, count) \ - TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ VERIFY_PROGRAM(project, filename, section_name, program_name, {}, &prevail::g_ebpf_platform_linux, true, \ count); \ } #define TEST_PROGRAM_FAIL(project, filename, section_name, program_name, count, kind) \ - TEST_CASE(project "/" filename " " program_name, "[!shouldfail][verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " program_name, "[!shouldfail][verify][samples][" project "]") { \ INFO("issue_kind=" << verify_test::to_string(kind)); \ VERIFY_PROGRAM(project, filename, section_name, program_name, {}, &prevail::g_ebpf_platform_linux, true, \ count); \ } #define TEST_PROGRAM_REJECT(project, filename, section_name, program_name, count) \ - TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ VERIFY_PROGRAM(project, filename, section_name, program_name, {}, &prevail::g_ebpf_platform_linux, false, \ count); \ } #define TEST_PROGRAM_REJECT_FAIL(project, filename, section_name, program_name, count) \ - TEST_CASE(project "/" filename " " program_name, "[!shouldfail][verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " program_name, "[!shouldfail][verify][samples][" project "]") { \ VERIFY_PROGRAM(project, filename, section_name, program_name, {}, &prevail::g_ebpf_platform_linux, false, \ count); \ } #define TEST_SECTION_REJECT(project, filename, section) \ - TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, false); \ } #define TEST_SECTION_REJECT_IF_STRICT(project, filename, section) \ - TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ + BOUNDED_TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ prevail::ebpf_verifier_options_t options{}; \ VERIFY_SECTION(project, filename, section, options, &prevail::g_ebpf_platform_linux, true); \ options.strict = true; \ VERIFY_SECTION(project, filename, section, options, &prevail::g_ebpf_platform_linux, false); \ } -#define TEST_SECTION_FAIL(project, filename, section, kind) \ - TEST_CASE("expect failure " project "/" filename " " section, "[!shouldfail][verify][samples][" project "]") { \ - INFO("issue_kind=" << verify_test::to_string(kind)); \ - VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ +#define TEST_SECTION_FAIL(project, filename, section, kind) \ + BOUNDED_TEST_CASE("expect failure " project "/" filename " " section, \ + "[!shouldfail][verify][samples][" project "]") { \ + INFO("issue_kind=" << verify_test::to_string(kind)); \ + VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ } -#define TEST_SECTION_SKIP(project, filename, section, kind) \ - TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ - SKIP(verify_test::to_string(kind)); \ +#define TEST_SECTION_SKIP(project, filename, section, kind) \ + BOUNDED_TEST_CASE(project "/" filename " " section, "[verify][samples][" project "]") { \ + SKIP(verify_test::to_string(kind)); \ } -#define TEST_PROGRAM_SKIP(project, filename, section_name, program_name, kind) \ - TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ - SKIP(verify_test::to_string(kind)); \ +#define TEST_PROGRAM_SKIP(project, filename, section_name, program_name, kind) \ + BOUNDED_TEST_CASE(project "/" filename " " program_name, "[verify][samples][" project "]") { \ + SKIP(verify_test::to_string(kind)); \ } -#define TEST_SECTION_REJECT_LOAD(project, filename, section) \ - TEST_CASE("expect load rejection " project "/" filename " " section, "[verify][samples][" project "]") { \ - REQUIRE_THROWS_AS(([&]() { \ - (void)verify_test::read_elf_cached("ebpf-samples/" project "/" filename, section, "", \ - {}, &prevail::g_ebpf_platform_linux); \ - }()), \ - std::runtime_error); \ +#define TEST_SECTION_REJECT_LOAD(project, filename, section) \ + BOUNDED_TEST_CASE("expect load rejection " project "/" filename " " section, "[verify][samples][" project "]") { \ + REQUIRE_THROWS_AS(([&]() { \ + (void)verify_test::read_elf_cached("ebpf-samples/" project "/" filename, section, "", \ + {}, &prevail::g_ebpf_platform_linux); \ + }()), \ + std::runtime_error); \ } #define TEST_SECTION_FAIL_SLOW(project, filename, section, kind) \ - TEST_CASE("expect failure " project "/" filename " " section, \ - "[!shouldfail][verify][samples][slow][" project "]") { \ + BOUNDED_TEST_CASE("expect failure " project "/" filename " " section, \ + "[!shouldfail][verify][samples][slow][" project "]") { \ INFO("issue_kind=" << verify_test::to_string(kind)); \ VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, true); \ } -#define TEST_SECTION_REJECT_FAIL(project, filename, section) \ - TEST_CASE("expect failure " project "/" filename " " section, "[!shouldfail][verify][samples][" project "]") { \ - VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, false); \ +#define TEST_SECTION_REJECT_FAIL(project, filename, section) \ + BOUNDED_TEST_CASE("expect failure " project "/" filename " " section, \ + "[!shouldfail][verify][samples][" project "]") { \ + VERIFY_SECTION(project, filename, section, {}, &prevail::g_ebpf_platform_linux, false); \ } #define TEST_SECTION_LEGACY(dirname, filename, sectionname) TEST_SECTION(dirname, filename, sectionname)