diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 990e2c1..d7360bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,5 +20,7 @@ jobs: arch: x64 - name: Build default features run: cargo build --locked --all-targets - - name: Unit tests + - name: Debug tests run: cargo test --locked --all-features --all-targets + - name: Release tests + run: cargo test --locked --release --all-features --all-targets diff --git a/docs/acceptance.md b/docs/acceptance.md index 7612b2f..c3144ae 100644 --- a/docs/acceptance.md +++ b/docs/acceptance.md @@ -17,7 +17,7 @@ 当前测试覆盖以下公共边界: -- Invoke API v5 envelope、严格 payload、单实例生命周期、panic 隔离和同步清理; +- Invoke API v5 envelope、严格 payload、单实例生命周期、运行时线程重入拒绝(Debug/Release)、panic 隔离和同步清理; - 配置修订版 13、IPv6 总开关、代理图、静态 `select` 代理组、节点测速配置和未知字段拒绝; - VLESS/XHTTP/TLS/REALITY、SOCKS5、AnyTLS 和代理链; - DNS wire、缓存、singleflight、policy、故障转移和 TCP 复用; @@ -32,6 +32,7 @@ ```bash cargo fmt --all -- --check cargo test --locked --all-features --all-targets +cargo test --locked --release --all-features --all-targets cargo clippy --locked --all-features --lib --bins -- -D warnings cargo test --manifest-path crates/vcore-netstack/Cargo.toml --all-targets cargo clippy --manifest-path crates/vcore-netstack/Cargo.toml --all-targets -- -D warnings diff --git a/docs/invoke-api.md b/docs/invoke-api.md index 530c3f9..5221abe 100644 --- a/docs/invoke-api.md +++ b/docs/invoke-api.md @@ -15,6 +15,7 @@ void VCoreFree(char *response); - 请求必须是以 NUL 结尾的 UTF-8 JSON。 - 非空响应由 VCore 分配,调用方必须使用同一库中的 `VCoreFree` 释放。 - 非法输入、未知方法、状态错误和 panic 返回合法失败 JSON;只有灾难性分配失败可以返回 `NULL`。 +- 业务运行时线程不能重入 Invoke;Debug 和 Release 构建都立即返回失败 JSON,包括 `version` 等只读请求。 - 请求正文、响应正文、完整配置、UUID、密钥、short ID 和凭据不得写入日志。 - `VCoreWindowsVpnInvoke` 是 Windows 安装包桥接接口,不属于业务 API v5。 - `VCoreWindowsVpnInvoke` 当前在调用线程上初始化 MTA;调用线程必须尚未初始化 COM,或已经是 MTA。STA/ASTA 调用不受支持。 diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index bded636..e3bd36c 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -208,7 +208,9 @@ struct RuntimeThreadGuard; impl RuntimeThreadGuard { fn enter() -> Self { IS_RUNTIME_THREAD.with(|marker| { - debug_assert!(!marker.replace(true)); + // Admission state must also be set when debug assertions are disabled. + let was_runtime_thread = marker.replace(true); + debug_assert!(!was_runtime_thread); }); Self }