feat: 新增 ASan 常设门脚本,批次收尾前跑全 workspace 单测

This commit is contained in:
2026-10-06 23:10:54 +00:00
parent ba34c961ba
commit 6b960ea45a
5 changed files with 127 additions and 22 deletions
Generated
+18 -18
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1225,7 +1225,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1234,7 +1234,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1253,7 +1253,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1267,7 +1267,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1282,7 +1282,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1291,7 +1291,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"bumpalo",
"dashmap",
@@ -1306,7 +1306,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1318,7 +1318,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"tracing",
"tracing-appender",
@@ -1327,7 +1327,7 @@ dependencies = [
[[package]]
name = "oxide_parser"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1342,7 +1342,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1358,7 +1358,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"num-bigint",
"num-traits",
@@ -1370,7 +1370,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1387,7 +1387,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"bumpalo",
"hashbrown 0.14.5",
@@ -1399,7 +1399,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.8.44"
version = "0.8.45"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -22,7 +22,7 @@ members = [
]
[workspace.package]
version = "0.8.44"
version = "0.8.45"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+15 -3
View File
@@ -52,6 +52,18 @@ fn wait_for_healthy(deadline: Duration) {
}
}
/// 轮询判 server 进程退出(50 毫秒间隔、给定截止)。
///
/// 删 sidecar 文件早于进程实际退出,二者间隙随构建环境变化(带内存
/// sanitizer 的构建 atexit 收尾更久),立即断言会撞上未退出窗口,故有界轮询。
fn wait_pid_dead(pid: u32, deadline: Duration) {
let end = Instant::now() + deadline;
while sidecar::pid_alive(pid) {
assert!(Instant::now() < end, "server 进程应在有界时间内退出");
std::thread::sleep(Duration::from_millis(50));
}
}
/// 发送请求帧并读回一帧响应。
fn send_and_recv(stream: &mut UnixStream, request: &ServerRequest) -> ServerResponse {
stream
@@ -200,7 +212,7 @@ fn server_start_e2e() {
assert!(!socket.exists(), "socket 文件应被删除");
assert!(!sidecar_path.exists(), "sidecar 文件应被删除");
assert!(!sidecar::pid_alive(id.pid), "server 进程应已退出");
wait_pid_dead(id.pid, Duration::from_secs(30));
}
/// start 双启动幂等:已有存活 server 时再跑 start,断言第二次退 0 且打印
@@ -393,7 +405,7 @@ fn server_log_e2e() {
assert!(Instant::now() < deadline, "server 应在有界时间内退出");
std::thread::sleep(Duration::from_millis(50));
}
assert!(!sidecar::pid_alive(id.pid), "server 进程应已退出");
wait_pid_dead(id.pid, Duration::from_secs(30));
// 日志文件有意保留(跨重启的诊断工件)。
assert!(log_path.exists(), "日志文件退出后应保留");
@@ -607,5 +619,5 @@ fn server_watchdog_sigint_stops_server() {
assert!(Instant::now() < deadline, "server 应在有界时间内退出");
std::thread::sleep(Duration::from_millis(50));
}
assert!(!sidecar::pid_alive(id.pid), "server 进程应已退出");
wait_pid_dead(id.pid, Duration::from_secs(30));
}
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# ASan 常设门:按地址 sanitizer 配方跑全 workspace 单测。
#
# 用法: scripts/asan_gate.sh
# 无参数。nightly 工具链加地址 sanitizer 构建并跑 cargo test --workspace。
#
# 配方说明:detect_leaks=0 因 PermInterner 与静态表设计性永久泄漏,
# 泄漏检测纯噪声;quarantine_size_mb=64 收隔离区,压高并发下内存放大。
# RUSTC 指到 asan_rustc_wrapper.sh:仅 oxide_* crate 带 sanitizer 插桩,
# 依赖树(含 proc-macro)不带(proc-macro 动态库加载约束,见包装器注释)。
#
# 退出码: 0 全部通过;1 构建失败或测试失败或 ASan 报告;2 nightly 工具链缺失。
set -u
cd "$(dirname "$0")/.."
# 前置检查:nightly 工具链必须已装(rust-toolchain.toml 钉 stable,须显式切换)。
if ! RUSTUP_TOOLCHAIN=nightly cargo --version >/dev/null 2>&1; then
echo "缺 nightly 工具链:rustup toolchain install nightly" >&2
exit 2
fi
export RUSTUP_TOOLCHAIN=nightly
export RUSTFLAGS="-Zsanitizer=address"
export CARGO_TARGET_DIR=target-asan
export ASAN_OPTIONS="detect_leaks=0:quarantine_size_mb=64"
# proc-macro 动态库加载进无 ASan 运行时的 rustc 会失败,
# 经包装器剥离其 sanitizer 标志(见包装器头部注释)。
export RUSTC="$PWD/scripts/asan_rustc_wrapper.sh"
cargo test --workspace
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# ASan 构建用 rustc 包装器:仅引擎 crate 与最终链接单元带地址 sanitizer 标志。
#
# 门的目标是检测引擎代码的真实内存错误,故只给 oxide_* 工作区 crate
# 插桩,整个依赖树(含 proc-macro)不带 sanitizer 编译。两个原因:
# 1. proc-macro 以动态库加载进未带 ASan 运行时的 rustc 进程,
# 带 sanitizer 的 proc-macro 动态库加载即失败(未定义 ASan 符号);
# 2. proc-macro 动态库把自身依赖(proc-macro2、syn 等)以 rlib 链入,
# 只剥 proc-macro 自身的标志不够,ASan 插桩的依赖仍会带进动态库。
#
# 最终链接单元(--test 测试目标、--crate-type bin 的二进制目标)也要带
# 标志:它们链入带插桩的引擎 rlib,须由 rustc 链接 ASan 运行时;
# 构建脚本(crate 名 build_script_build)是独立可执行文件,不插桩。
#
# 用法:常设门把 RUSTC 指到本脚本。按 --crate-name 与编译类型参数裁决,
# 保留或剥离 -Zsanitizer=address 后透传给 rustc。
crate_name=""
is_bin=0
has_test=0
prev=""
for a in "$@"; do
if [ "$prev" = "--crate-name" ]; then
crate_name="$a"
fi
if [ "$prev" = "--crate-type" ]; then
case "$a" in
bin) is_bin=1 ;;
esac
fi
case "$a" in
--crate-type=bin) is_bin=1 ;;
--test) has_test=1 ;;
esac
prev="$a"
done
keep=0
case "$crate_name" in
build_script_build) ;;
oxide*) keep=1 ;;
*)
if [ "$is_bin" -eq 1 ] || [ "$has_test" -eq 1 ]; then
keep=1
fi
;;
esac
if [ "$keep" -eq 1 ]; then
exec rustc "$@"
fi
out=()
for a in "$@"; do
case "$a" in
-Zsanitizer=address) continue ;;
esac
out+=("$a")
done
exec rustc "${out[@]}"