code wiki / _hdl_build / nx_xlate_gap_gate.nx
nx_xlate_gap_gate.nx source
↩ module page · 110 lines · 5582 B
1// nx_xlate_gap_gate.nx -- regression gate for the NXASM-SYSCALL-XLATE-GAP class: every syscall once
2// filed as untranslated (mkdirat-34, renameat2-276 via the 2026-06-06 table rows; fsync-74 and
3// unlinkat-263 via the proven direct-x86 escape hatch) must BEHAVE at runtime under the CURRENT
4// blessed toolchain. Each row is a discriminating pair where possible (valid input succeeds AND
5// invalid input fails with the right errno), so a pass cannot be a silent no-op.
6// Durable: XLATE-ROW + XLATE-GATE lines -> knowledge/status/xlate_gap_gate.log. Exit 0 iff all rows
7// PASS. Owner: Engineer. Resolves sentinel key NXASM-XLATE-GAP. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9const AT_FDCWD: i64 = 0 - 100
10func _p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
11func _fs(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
12func _fn(fd: i64, v: i64) -> i64 {
13 let b: *u8 = sys_mmap(32)
14 var x: i64 = v
15 if x < 0 { _fs(fd, "-" as *u8); x = 0 - x }
16 var i: i64 = 31
17 b[i] = 0 as u8
18 i = i - 1
19 if x == 0 { b[i] = 48 as u8; i = i - 1 }
20 while x > 0 { b[i] = ((x - (x / 10) * 10) + 48) as u8; x = x / 10; i = i - 1 }
21 let base: i64 = b as i64
22 _fs(fd, (base + i + 1) as *u8)
23 return 0
24}
25func xg_unlink(p: *u8) -> i64 { return __syscall(263, AT_FDCWD, p, 0, 0, 0, 0) }
26func xg_rmdir(p: *u8) -> i64 { return __syscall(263, AT_FDCWD, p, 512, 0, 0, 0) } // unlinkat AT_REMOVEDIR(0x200)
27// hermetic fixture reset (rule 10 idempotent): clear any leftover from a crashed/prior run so a stale
28// dir/file can never spuriously RED this gate. Best-effort -- errors ignored (paths may not exist).
29func xg_clean() -> i64 {
30 xg_unlink("/tmp/_xg_dir/f" as *u8)
31 xg_unlink("/tmp/_xg_dir/f.new" as *u8)
32 xg_unlink("/tmp/_xg_dir/f.live" as *u8)
33 xg_rmdir("/tmp/_xg_dir" as *u8)
34 return 0
35}
36func xg_row(lfd: i64, name: *u8, ok: i64, rc1: i64, rc2: i64) -> i64 {
37 _p(" " as *u8); _p(name); _p(": rc1=" as *u8); _fn(1, rc1); _p(" rc2=" as *u8); _fn(1, rc2)
38 _fs(lfd, "XLATE-ROW name=" as *u8); _fs(lfd, name)
39 _fs(lfd, " rc1=" as *u8); _fn(lfd, rc1); _fs(lfd, " rc2=" as *u8); _fn(lfd, rc2)
40 if ok == 1 { _p(" PASS\n" as *u8); _fs(lfd, " verdict=PASS\n" as *u8) }
41 if ok != 1 { _p(" FAIL\n" as *u8); _fs(lfd, " verdict=FAIL\n" as *u8) }
42 return 0
43}
44func main() -> i64 {
45 _p("=== XLATE GAP GATE: every once-gapped syscall behaves under the current blessed toolchain ===\n" as *u8)
46 let lfd: i64 = sys_openat_append("knowledge/status/xlate_gap_gate.log" as *u8, 0x1a4)
47 if lfd < 0 { _p(" gate log open FAILED -- loud fail\n" as *u8); sys_exit(1); return 1 }
48 xg_clean() // hermetic START: a stale fixture (e.g. a root-owned /tmp/_xg_dir from a prior sudo run) must not poison the test
49 var pass: i64 = 0
50
51 // [1] mkdirat (rv64 34 -> x86 258, table row): create ok or already-exists; a bogus nested path fails
52 let d: *u8 = "/tmp/_xg_dir" as *u8
53 let r1a: i64 = sys_mkdir(d, 0x1ed)
54 let r1b: i64 = sys_mkdir("/tmp/_xg_nodir/sub" as *u8, 0x1ed)
55 var ok1: i64 = 0
56 if r1a == 0 { ok1 = 1 }
57 if r1a == (0 - 17) { ok1 = 1 }
58 if r1b >= 0 { ok1 = 0 }
59 xg_row(lfd, "mkdirat-34" as *u8, ok1, r1a, r1b)
60 pass = pass + ok1
61
62 // [2] fsync (direct x86 74): 0 on a valid fd, -9 EBADF on a bad fd (discriminating pair)
63 let f: *u8 = "/tmp/_xg_dir/f" as *u8
64 let wfd: i64 = sys_openat_wr(f, 0x1a4)
65 sys_write(wfd, "xlate-gap-gate\n" as *u8, 15)
66 let r2a: i64 = sys_fsync(wfd)
67 sys_close(wfd)
68 let r2b: i64 = sys_fsync(9999)
69 var ok2: i64 = 0
70 if r2a == 0 { if r2b == (0 - 9) { ok2 = 1 } }
71 xg_row(lfd, "fsync-74" as *u8, ok2, r2a, r2b)
72 pass = pass + ok2
73
74 // [3] renameat2 (rv64 276 -> x86 316, table row): atomic swap then the live path reads back
75 let fn2: *u8 = "/tmp/_xg_dir/f.new" as *u8
76 let fl: *u8 = "/tmp/_xg_dir/f.live" as *u8
77 let nfd: i64 = sys_openat_wr(fn2, 0x1a4)
78 sys_write(nfd, "live\n" as *u8, 5)
79 sys_close(nfd)
80 let r3a: i64 = sys_renameat(fn2, fl)
81 let rfd: i64 = sys_openat_rd(fl)
82 var ok3: i64 = 0
83 if r3a == 0 { if rfd >= 0 { ok3 = 1 } }
84 if rfd >= 0 { sys_close(rfd) }
85 xg_row(lfd, "renameat2-276" as *u8, ok3, r3a, rfd)
86 pass = pass + ok3
87
88 // [4] unlinkat (direct x86 263): removes the live file; a re-open then fails
89 let r4a: i64 = xg_unlink(fl)
90 let gone: i64 = sys_openat_rd(fl)
91 var ok4: i64 = 0
92 if r4a == 0 { if gone < 0 { ok4 = 1 } }
93 if gone >= 0 { sys_close(gone) }
94 xg_row(lfd, "unlinkat-263" as *u8, ok4, r4a, gone)
95 pass = pass + ok4
96
97 xg_unlink(f)
98 xg_unlink(fl) // row 4 already removed it; best-effort
99 xg_rmdir(d) // best-effort; NB unlinkat+AT_REMOVEDIR(512) does NOT remove the dir here (flags-arg
100 // translation gap for syscall 263 -- flags=0 unlink works, =512 rmdir no-ops). Harmless:
101 // the empty USER-OWNED dir is reused + writable, and xg_clean() at START guarantees idempotency.
102 _fs(lfd, "XLATE-GATE rows=4 pass=" as *u8); _fn(lfd, pass)
103 if pass == 4 { _fs(lfd, " verdict=GREEN\n" as *u8) } else { _fs(lfd, " verdict=RED\n" as *u8) }
104 sys_close(lfd)
105 _p(" --- XLATE GATE: " as *u8); _fn(1, pass); _p("/4 rows ---\n" as *u8)
106 if pass == 4 { _p(" XLATE GAP GATE: GREEN (gap class closed under current bless)\n" as *u8); sys_exit(0); return 0 }
107 _p(" XLATE GAP GATE: RED (a gap regressed -- fix the toolchain, never the gate)\n" as *u8)
108 sys_exit(1)
109 return 1
110}