Skip to content

Commit 21807be

Browse files
committed
补充C++17原生与WASM语法边界验收证据
1 parent 9b5056b commit 21807be

4 files changed

Lines changed: 303 additions & 1 deletion

File tree

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#![cfg(all(feature = "wasm-precheck", unix))]
2+
3+
use sha2::{Digest, Sha256};
4+
use std::fs;
5+
use std::process::Command;
6+
7+
/// 使用既有工具比较 C++17 语法,类型语义单独保留。
8+
#[test]
9+
#[ignore = "requires explicit existing Apple clang21 via CODEGUARD_CLANG_BIN"]
10+
fn cpp17_native_and_wasm_syntax_boundaries() {
11+
let clang = std::env::var("CODEGUARD_CLANG_BIN").expect("explicit existing compiler");
12+
let version = Command::new(&clang).arg("--version").output().unwrap();
13+
assert!(version.status.success());
14+
assert!(
15+
String::from_utf8_lossy(&version.stdout)
16+
.starts_with("Apple clang version 21.0.0 (clang-2100.3.34.2)")
17+
);
18+
let root = std::env::temp_dir().canonicalize().unwrap().join(format!(
19+
"codeguard-cpp17-differential-{}",
20+
std::process::id()
21+
));
22+
fs::create_dir_all(&root).unwrap();
23+
let cases = [
24+
(
25+
"namespace",
26+
"namespace n { int f() { return 1; } }",
27+
true,
28+
true,
29+
),
30+
(
31+
"template",
32+
"template<class T> T identity(T x) { return x; }",
33+
true,
34+
true,
35+
),
36+
(
37+
"lambda",
38+
"int f() { auto g = [](int x) { return x + 1; }; return g(1); }",
39+
true,
40+
true,
41+
),
42+
(
43+
"structured_binding",
44+
"struct P { int x; int y; }; int f() { auto [x,y] = P{1,2}; return x+y; }",
45+
true,
46+
true,
47+
),
48+
(
49+
"constexpr_if",
50+
"template<class T> int f(T x) { if constexpr(sizeof(T)>1) return 1; else return 0; }",
51+
true,
52+
true,
53+
),
54+
(
55+
"fold_expression",
56+
"template<class... T> auto sum(T... x) { return (x + ...); }",
57+
true,
58+
true,
59+
),
60+
(
61+
"raw_string",
62+
"const char *s = R\"tag(a\"b)tag\";",
63+
true,
64+
true,
65+
),
66+
("missing_brace", "int f() { return 0;", false, false),
67+
("missing_expression", "int f() { return ; + }", false, false),
68+
("missing_semicolon", "int value = 1", false, false),
69+
("type_mismatch", "int value = \"text\";", false, true),
70+
("unknown_symbol", "int f() { return absent; }", false, true),
71+
];
72+
let mut observations = Vec::new();
73+
for (name, source, native_valid, wasm_valid) in cases {
74+
let file = root.join(format!("{name}.cpp"));
75+
fs::write(&file, source).unwrap();
76+
let native = Command::new(&clang)
77+
.args([
78+
"-fsyntax-only",
79+
"-std=c++17",
80+
"-Wno-everything",
81+
"-x",
82+
"c++",
83+
])
84+
.arg(&file)
85+
.output()
86+
.unwrap();
87+
assert!(
88+
matches!(native.status.code(), Some(0 | 1)),
89+
"{name}: {native:?}"
90+
);
91+
assert_eq!(
92+
native.status.success(),
93+
native_valid,
94+
"{name}: {}",
95+
String::from_utf8_lossy(&native.stderr)
96+
);
97+
let candidate = Command::new(env!("CARGO_BIN_EXE_codeguard"))
98+
.args(["grammar", "probe", "cpp"])
99+
.arg(&file)
100+
.arg("--format=json")
101+
.output()
102+
.unwrap();
103+
assert_eq!(candidate.status.code(), Some(3), "{name}: {candidate:?}");
104+
let report: serde_json::Value = serde_json::from_slice(&candidate.stdout).unwrap();
105+
assert_eq!(report["grammar_qualified"], false);
106+
assert_eq!(report["delivery_decision"], "not_evaluated");
107+
assert!(report["reason"].is_null(), "{name}: {report}");
108+
assert_eq!(
109+
report["recoveries"].as_array().unwrap().is_empty(),
110+
wasm_valid,
111+
"{name}: {report}"
112+
);
113+
assert_eq!(fs::read_to_string(&file).unwrap(), source);
114+
observations.push(serde_json::json!({
115+
"name": name,
116+
"source_sha256": format!("{:x}", Sha256::digest(source.as_bytes())),
117+
"native_exit_code": native.status.code(),
118+
"native_valid": native.status.success(),
119+
"wasm_valid": report["recoveries"].as_array().unwrap().is_empty(),
120+
"expected_native_valid": native_valid,
121+
"expected_wasm_valid": wasm_valid,
122+
"grammar_qualified": report["grammar_qualified"],
123+
"delivery_decision": report["delivery_decision"]
124+
}));
125+
}
126+
fs::remove_dir_all(root).unwrap();
127+
if let Ok(destination) = std::env::var("CODEGUARD_CPP_DIFFERENTIAL_EVIDENCE") {
128+
let path = std::path::Path::new(&destination);
129+
assert!(path.is_absolute(), "evidence destination must be absolute");
130+
let evidence = serde_json::json!({
131+
"schema_version": "0.1",
132+
"language": "cpp",
133+
"standard": "c++17",
134+
"qualification": "not_granted",
135+
"corpus_kind": "author_regression_not_independent_holdout",
136+
"compiler_version": String::from_utf8_lossy(&version.stdout).trim(),
137+
"compiler_sha256": format!("{:x}", Sha256::digest(fs::read(&clang).unwrap())),
138+
"cli_sha256": format!("{:x}", Sha256::digest(fs::read(env!("CARGO_BIN_EXE_codeguard")).unwrap())),
139+
"test_source_sha256": format!("{:x}", Sha256::digest(include_bytes!("cpp_native_differential.rs"))),
140+
"cases": observations
141+
});
142+
fs::write(path, serde_json::to_vec_pretty(&evidence).unwrap()).unwrap();
143+
}
144+
}

‎openspec/changes/introduce-rust-codeguard-cli/tasks.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@
345345
- [ ] 8.26 实现 c 的 lint/comments 适配与规则;验收:真实工具正确样本和违规样本、错误配置/版本/报告反例通过,格式化不能冒充注释检查。
346346
- [ ] 8.27 完成 c 的 dependencies/CVE/security/build 适用能力及整体验收;验收:依赖生态映射和逐类别真实证据齐备,缺口未解决不升级 stable。
347347
- [ ] 8.28 为 cpp 固化六类别适用性、候选工具/方言/版本及缺口;验收:每个槽位有实际依据,not_applicable 不得用缺工具解释。
348-
- [ ] 8.29 实现 cpp 的 lint/comments 适配与规则;验收:真实工具正确样本和违规样本、错误配置/版本/报告反例通过,格式化不能冒充注释检查。
348+
- [ ] 8.29 实现 cpp 的 lint/comments 适配与规则;验收:真实工具正确样本和违规样本、错误配置/版本/报告反例通过,格式化不能冒充注释检查。 新增C++17局部原生/WASM对照:12例实际执行,包含2例语义边界;1测试通过、0忽略,未授予生产资格,见[验收记录](../../../tests/acceptance/cpp17-native-wasm-differential.md)。
349349
- [ ] 8.30 完成 cpp 的 dependencies/CVE/security/build 适用能力及整体验收;验收:依赖生态映射和逐类别真实证据齐备,缺口未解决不升级 stable。
350350
- [ ] 8.31 为 objc 固化六类别适用性、候选工具/方言/版本及缺口;验收:每个槽位有实际依据,not_applicable 不得用缺工具解释。
351351
- [ ] 8.32 实现 objc 的 lint/comments 适配与规则;验收:真实工具正确样本和违规样本、错误配置/版本/报告反例通过,格式化不能冒充注释检查。
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# C++17 原生与 WASM 对照局部验收
2+
3+
对应 introduce-rust-codeguard-cli 的 8.29、15.2、15.7。使用现有 Apple clang 21.0.0 (clang-2100.3.34.2),不安装工具。
4+
5+
命令:`CARGO_PROFILE_TEST_DEBUG=0 CODEGUARD_CLANG_BIN=/usr/bin/clang cargo test --offline --locked -p codeguard-cli --features wasm-precheck --test cpp_native_differential -- --include-ignored`。
6+
7+
格式化后的实际结果:1 passed、0 failed、0 ignored,17.81秒。12例全部执行原生和CLI grammar probe:7例合法语法(namespace/template/lambda/structured binding/constexpr if/fold expression/raw string)、3例损坏语法、2例类型或未知符号错误。最后两例原生拒绝而WASM接受,刻意不将语法成功解释为语义检查通过。全部检查源码未被修改、候选资格false、delivery_decision为not_evaluated。
8+
9+
测试源码SHA256:`10c540b6e49de7fad3551dc34578f040721d961481442fc2663a3a38ffd4f867`。
10+
11+
这是作者回归语料与本机真实工具对照,不是独立盲测、项目构建配置、头文件、平台矩阵或真实宿主验收。不升级C++资格,不勾选父任务,32 grammar生产资格仍为0。
12+
13+
[机器证据](evidence/cpp17-native-wasm-differential.json)记录工具版本、编译器及CLI摘要、逐例输入摘要和实际原生/WASM结果;仅在全部断言通过后写出。证据采集环境变量为CODEGUARD_CPP_DIFFERENTIAL_EVIDENCE,必须为绝对路径。
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
{
2+
"cases": [
3+
{
4+
"delivery_decision": "not_evaluated",
5+
"expected_native_valid": true,
6+
"expected_wasm_valid": true,
7+
"grammar_qualified": false,
8+
"name": "namespace",
9+
"native_exit_code": 0,
10+
"native_valid": true,
11+
"source_sha256": "a8aa0d1bea17602986a75232c927433f53158dcfe20c149cce11b5f4410da32e",
12+
"wasm_valid": true
13+
},
14+
{
15+
"delivery_decision": "not_evaluated",
16+
"expected_native_valid": true,
17+
"expected_wasm_valid": true,
18+
"grammar_qualified": false,
19+
"name": "template",
20+
"native_exit_code": 0,
21+
"native_valid": true,
22+
"source_sha256": "ef12cb4ccdc5736c4177fee0aad6b1a947deeda5118d337f0902b898e0bd02d7",
23+
"wasm_valid": true
24+
},
25+
{
26+
"delivery_decision": "not_evaluated",
27+
"expected_native_valid": true,
28+
"expected_wasm_valid": true,
29+
"grammar_qualified": false,
30+
"name": "lambda",
31+
"native_exit_code": 0,
32+
"native_valid": true,
33+
"source_sha256": "5477ba29161c26796f382d8c5cdefe08a918271fe564ac76f053f368e0427f8a",
34+
"wasm_valid": true
35+
},
36+
{
37+
"delivery_decision": "not_evaluated",
38+
"expected_native_valid": true,
39+
"expected_wasm_valid": true,
40+
"grammar_qualified": false,
41+
"name": "structured_binding",
42+
"native_exit_code": 0,
43+
"native_valid": true,
44+
"source_sha256": "5e9da4f80d1acc11a8f9e6fbc0ba26cb02ec74770728fb71752f1d56ef1e1273",
45+
"wasm_valid": true
46+
},
47+
{
48+
"delivery_decision": "not_evaluated",
49+
"expected_native_valid": true,
50+
"expected_wasm_valid": true,
51+
"grammar_qualified": false,
52+
"name": "constexpr_if",
53+
"native_exit_code": 0,
54+
"native_valid": true,
55+
"source_sha256": "55596de93b3a07be196063e140b56564b13c92937f42028e2d40e8806cbdb7c2",
56+
"wasm_valid": true
57+
},
58+
{
59+
"delivery_decision": "not_evaluated",
60+
"expected_native_valid": true,
61+
"expected_wasm_valid": true,
62+
"grammar_qualified": false,
63+
"name": "fold_expression",
64+
"native_exit_code": 0,
65+
"native_valid": true,
66+
"source_sha256": "94b696a15c508b5c38dc4533832437d481885c483010ea2ba9995daa5737f9cf",
67+
"wasm_valid": true
68+
},
69+
{
70+
"delivery_decision": "not_evaluated",
71+
"expected_native_valid": true,
72+
"expected_wasm_valid": true,
73+
"grammar_qualified": false,
74+
"name": "raw_string",
75+
"native_exit_code": 0,
76+
"native_valid": true,
77+
"source_sha256": "01da61bc2350409913e1f96cf53b57128032269cff0580e5c7204eebf56c341e",
78+
"wasm_valid": true
79+
},
80+
{
81+
"delivery_decision": "not_evaluated",
82+
"expected_native_valid": false,
83+
"expected_wasm_valid": false,
84+
"grammar_qualified": false,
85+
"name": "missing_brace",
86+
"native_exit_code": 1,
87+
"native_valid": false,
88+
"source_sha256": "534e5f4b9fdd0986541bc66ecad7ec916eb7c06aeee84a86995bff07a3945bd4",
89+
"wasm_valid": false
90+
},
91+
{
92+
"delivery_decision": "not_evaluated",
93+
"expected_native_valid": false,
94+
"expected_wasm_valid": false,
95+
"grammar_qualified": false,
96+
"name": "missing_expression",
97+
"native_exit_code": 1,
98+
"native_valid": false,
99+
"source_sha256": "2c3141ba22c384ba74e89a0ef76ef8979f5fd7d895b62dcdca7a7436cf22d1a6",
100+
"wasm_valid": false
101+
},
102+
{
103+
"delivery_decision": "not_evaluated",
104+
"expected_native_valid": false,
105+
"expected_wasm_valid": false,
106+
"grammar_qualified": false,
107+
"name": "missing_semicolon",
108+
"native_exit_code": 1,
109+
"native_valid": false,
110+
"source_sha256": "8e9828d992585a4df8f1203ac81f02e5c363c4f7f18f4652557349816cd6a8b1",
111+
"wasm_valid": false
112+
},
113+
{
114+
"delivery_decision": "not_evaluated",
115+
"expected_native_valid": false,
116+
"expected_wasm_valid": true,
117+
"grammar_qualified": false,
118+
"name": "type_mismatch",
119+
"native_exit_code": 1,
120+
"native_valid": false,
121+
"source_sha256": "7d26cfc2c895e133a0599c85fb083288f395adc723a2576bc10882e81a9c69d6",
122+
"wasm_valid": true
123+
},
124+
{
125+
"delivery_decision": "not_evaluated",
126+
"expected_native_valid": false,
127+
"expected_wasm_valid": true,
128+
"grammar_qualified": false,
129+
"name": "unknown_symbol",
130+
"native_exit_code": 1,
131+
"native_valid": false,
132+
"source_sha256": "c10b9dcacad024a1a37eab09f2b1bda22f030fdfe4cd8dcdbfa39f819871a4ff",
133+
"wasm_valid": true
134+
}
135+
],
136+
"cli_sha256": "4efcd15e4b21b2fa25f081493e0c567a87b814348f17ac944bdae9e9fe3948c2",
137+
"compiler_sha256": "34129c71a01a74f7f3b2443521519b2e5447553fa187f5fcafaaf8c42cc192e2",
138+
"compiler_version": "Apple clang version 21.0.0 (clang-2100.3.34.2)\nTarget: arm64-apple-darwin27.0.0\nThread model: posix\nInstalledDir: /Library/Developer/CommandLineTools/usr/bin",
139+
"corpus_kind": "author_regression_not_independent_holdout",
140+
"language": "cpp",
141+
"qualification": "not_granted",
142+
"schema_version": "0.1",
143+
"standard": "c++17",
144+
"test_source_sha256": "10c540b6e49de7fad3551dc34578f040721d961481442fc2663a3a38ffd4f867"
145+
}

0 commit comments

Comments
 (0)