Files
Evan Hu 1c25466511 test(ci): 给解析不可信输入的宿主无关代码加 ASan / UBSan
MSIME-Linux 的 ci.yml 注释里已经写下了这个结论:「前端层才是解析不可信输入的那层……Windows 前端上次审计修的就是一批 race 和空指针,现有的 Debug 构建一个都抓不到。」Linux 仓照这个结论补了 sanitizer job,Windows 仓一条都没有。

给整个 Server 上 sanitizer 意味着要在 Windows runner 上做一份带 sanitizer 的 Boost、curl、sqlite 和 WebView2,代价很高。这里换一个能立刻落地的做法:把宿主无关的解析与策略代码单独建成一个不依赖任何包管理器的小目标,在 Linux runner 上用 ASan + UBSan 跑,几秒钟完成,每个 PR 都跑。

覆盖面确实小于全量 sanitize 构建,但它是真的在跑。目标从皮肤 CSS 策略起步,后续凡是能与 Windows 头文件解耦的、读取用户没写过的数据的逻辑(词库文件、IPC 负载、配置解析)都可以加进这个列表。

该目标同时以 -Wall -Wextra -Wpedantic -Werror 编译,与 Linux、Apple 两仓的标准一致。本机已用 ASan+UBSan 构建并运行通过。
2026-09-06 18:11:37 +09:00

46 lines
1.2 KiB
C++

// The main test executable's runner formats with fmt. This one deliberately depends on nothing
// outside the standard library, so that a sanitized build needs no package manager.
#include <cstdio>
#include <exception>
#include "tests/includes/test_framework.h"
namespace test
{
std::vector<TestCase> &registry()
{
static std::vector<TestCase> tests;
return tests;
}
Registrar::Registrar(const char *name, std::function<void()> fn)
{
registry().push_back({name, std::move(fn)});
}
} // namespace test
int main()
{
int failures = 0;
for (const auto &test_case : test::registry())
{
try
{
test_case.fn();
std::printf("[PASS] %s\n", test_case.name.c_str());
}
catch (const std::exception &ex)
{
++failures;
std::fprintf(stderr, "[FAIL] %s: %s\n", test_case.name.c_str(), ex.what());
}
catch (...)
{
++failures;
std::fprintf(stderr, "[FAIL] %s: unknown exception\n", test_case.name.c_str());
}
}
std::printf("%zu test(s), %d failure(s)\n", test::registry().size(), failures);
return failures == 0 ? 0 : 1;
}