nx_sendcheck_gate.nx source
↩ module page · 132 lines · 8557 B
1// nx_sendcheck_gate.nx -- LN6 (lang.plan): DATA-RACE TYPING AT THE THREAD-POOL BOUNDARY. End-to-end over the
2// PROMOTED compiler: four fixtures are assembled at runtime in /tmp/<gate>/ (never a file a source census
3// could mistake for an organ), the compiler is forked on each with stderr captured, and the teeth read the
4// captured bytes. Each fixture declares its own nx_pool_submit stub (the check is keyed on the callee NAME,
5// so the real pool and its threads are not needed):
6// fx_unmarked `struct Job { .. }` handed as `j as i64` under --sendcheck -> MUST be refused, naming Job,
7// with where (caret), why and fix (the teaching voice)
8// fx_marked `struct Job send { .. }` the same call under --sendcheck -> MUST compile (the marker works)
9// fx_int a plain integer ctx under --sendcheck -> MUST compile (declared abstention)
10// fx_default fx_unmarked WITHOUT the flag -> MUST compile (default unchanged)
11// The refusal is the LN6 contract; the three controls keep the gate from passing on a compiler that
12// refuses everything, on one that ignores the marker, or on one that changed the default. Byte-identity
13// of default builds is nx_cc_equiv_gate's job (10 rows + self-host), deliberately not duplicated here.
14// nx_sendcheck_gate -- verdict in the exit code (gv_verdict)
15// license_tier: ORIGINAL layer: lang module: nishi-core.lang.sendcheck_gate
16import "nx_syscalls.nx"
17import "nx_gate_verdict.nx"
18
19const SG_DIR: *u8 = "/tmp/nx_sendcheck_gate\x00" as *u8
20const SG_UNMARKED: *u8 = "/tmp/nx_sendcheck_gate/fx_unmarked.nx\x00" as *u8
21const SG_MARKED: *u8 = "/tmp/nx_sendcheck_gate/fx_marked.nx\x00" as *u8
22const SG_INT: *u8 = "/tmp/nx_sendcheck_gate/fx_int.nx\x00" as *u8
23const SG_ERR_U: *u8 = "/tmp/nx_sendcheck_gate/fx_unmarked.err\x00" as *u8
24const SG_ERR_M: *u8 = "/tmp/nx_sendcheck_gate/fx_marked.err\x00" as *u8
25const SG_ERR_I: *u8 = "/tmp/nx_sendcheck_gate/fx_int.err\x00" as *u8
26const SG_ERR_D: *u8 = "/tmp/nx_sendcheck_gate/fx_default.err\x00" as *u8
27const SG_DEVNULL: *u8 = "/dev/null\x00" as *u8
28const SG_FLAG: *u8 = "--sendcheck\x00" as *u8
29const SG_CC_NAS: *u8 = "buildroot/_offc/nx_cc_sovereign.elf\x00" as *u8 // NAS gate CWD = nishihost root
30const SG_CC_LAP: *u8 = "_offc/nx_cc_sovereign.elf\x00" as *u8 // laptop CWD = nxc2 root
31const SG_CAP: i64 = 65536
32const SG_MODE: i64 = 420
33
34func sg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func sg_w(s: *u8) -> i64 { sys_write(1, s, sg_slen(s)); return 0 }
36func sg_find(b: *u8, n: i64, pat: *u8) -> i64 {
37 let pl: i64 = sg_slen(pat)
38 if pl <= 0 { return 0 - 1 }
39 var i: i64 = 0
40 while i + pl <= n {
41 var j: i64 = 0; var ok: i64 = 1
42 while j < pl { if b[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } }
43 if ok == 1 { return i }
44 i = i + 1
45 }
46 return 0 - 1
47}
48func sg_write_file(path: *u8, body: *u8) -> i64 {
49 let fd: i64 = sys_openat_wr(path, SG_MODE)
50 if fd < 0 { return 0 - 1 }
51 let n: i64 = sg_slen(body)
52 sys_write(fd, body, n)
53 sys_close(fd)
54 return n
55}
56// fork the compiler on src (optionally with one flag first) with stderr -> errpath; exit code, -1 on fork fail.
57func sg_compile(cc: *u8, flag: *u8, src: *u8, errpath: *u8) -> i64 {
58 let pid: i64 = sys_fork()
59 if pid < 0 { return 0 - 1 }
60 if pid == 0 {
61 let dn: i64 = sys_openat_wr(SG_DEVNULL, SG_MODE)
62 if dn >= 0 { sys_dup3(dn, 1, 0) }
63 let ef: i64 = sys_openat_wr(errpath, SG_MODE)
64 if ef >= 0 { sys_dup3(ef, 2, 0) }
65 let argv: *i64 = sys_mmap(40) as *i64
66 var ai: i64 = 0
67 argv[ai] = cc as i64; ai = ai + 1
68 if (flag as i64) != 0 { argv[ai] = flag as i64; ai = ai + 1 }
69 argv[ai] = src as i64; ai = ai + 1
70 argv[ai] = 0
71 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
72 sys_execve(cc, argv, envp)
73 sys_exit_group(127)
74 }
75 let st: *i64 = sys_mmap(16) as *i64
76 sys_wait4(pid, st, 0)
77 return (st[0] >> 8) & 0xff
78}
79func sg_read(path: *u8, buf: *u8, cap: i64) -> i64 {
80 let fd: i64 = sys_openat_rd(path)
81 if fd < 0 { return 0 - 1 }
82 var tot: i64 = 0; var go: i64 = 1
83 while go == 1 {
84 let n: i64 = sys_read(fd, ((buf as i64) + tot) as *u8, cap - tot)
85 if n <= 0 { go = 0 } else { tot = tot + n; if tot >= cap { go = 0 } }
86 }
87 sys_close(fd)
88 return tot
89}
90func sg_pick_cc() -> *u8 {
91 let fd: i64 = sys_openat_rd(SG_CC_NAS)
92 if fd >= 0 { sys_close(fd); return SG_CC_NAS }
93 return SG_CC_LAP
94}
95
96func main() -> i64 {
97 let c: *i64 = gv_ctr()
98 sys_mkdir(SG_DIR, 493)
99 let cc: *u8 = sg_pick_cc()
100 sg_w(" compiler=" as *u8); sg_w(cc); sg_w("\n" as *u8)
101 // fixtures assembled at RUNTIME; no imports, so they resolve from any CWD.
102 let w1: i64 = sg_write_file(SG_UNMARKED, "struct Job { a: i64, b: i64 }\nfunc nx_pool_submit(pool: i64, fn: func(i64) -> i64, ctx: i64) -> i64 { return 0 }\nfunc task(c: i64) -> i64 { return c }\nfunc main() -> i64 {\n let j: *Job = 4096 as *Job\n return nx_pool_submit(0, task, j as i64)\n}\n" as *u8)
103 let w2: i64 = sg_write_file(SG_MARKED, "struct Job send { a: i64, b: i64 }\nfunc nx_pool_submit(pool: i64, fn: func(i64) -> i64, ctx: i64) -> i64 { return 0 }\nfunc task(c: i64) -> i64 { return c }\nfunc main() -> i64 {\n let j: *Job = 4096 as *Job\n return nx_pool_submit(0, task, j as i64)\n}\n" as *u8)
104 let w3: i64 = sg_write_file(SG_INT, "struct Job { a: i64, b: i64 }\nfunc nx_pool_submit(pool: i64, fn: func(i64) -> i64, ctx: i64) -> i64 { return 0 }\nfunc task(c: i64) -> i64 { return c }\nfunc main() -> i64 {\n let k: i64 = 7\n return nx_pool_submit(0, task, k)\n}\n" as *u8)
105 gv_check("fixtures-written-to-tmp-gate-dir" as *u8, (w1 > 0) & (w2 > 0) & (w3 > 0), c)
106
107 let rc_u: i64 = sg_compile(cc, SG_FLAG, SG_UNMARKED, SG_ERR_U)
108 let rc_m: i64 = sg_compile(cc, SG_FLAG, SG_MARKED, SG_ERR_M)
109 let rc_i: i64 = sg_compile(cc, SG_FLAG, SG_INT, SG_ERR_I)
110 let rc_d: i64 = sg_compile(cc, 0 as *u8, SG_UNMARKED, SG_ERR_D)
111 let eu: *u8 = sys_mmap(SG_CAP); let nu: i64 = sg_read(SG_ERR_U, eu, SG_CAP - 1)
112 let em: *u8 = sys_mmap(SG_CAP); let nm: i64 = sg_read(SG_ERR_M, em, SG_CAP - 1)
113 let ei: *u8 = sys_mmap(SG_CAP); let ni: i64 = sg_read(SG_ERR_I, ei, SG_CAP - 1)
114 let ed: *u8 = sys_mmap(SG_CAP); let nd: i64 = sg_read(SG_ERR_D, ed, SG_CAP - 1)
115 sg_w(" unmarked+flag rc=" as *u8); gv_num(rc_u); sg_w(" marked+flag rc=" as *u8); gv_num(rc_m)
116 sg_w(" int+flag rc=" as *u8); gv_num(rc_i); sg_w(" unmarked-default rc=" as *u8); gv_num(rc_d); sg_w("\n" as *u8)
117 if nu > 0 { sg_w(" unmarked stderr head: " as *u8); var k: i64 = 0; while k < nu { if k < 160 { if eu[k] == (10 as u8) { k = nu } else { sys_write(1, ((eu as i64) + k) as *u8, 1) } } k = k + 1 } sg_w("\n" as *u8) }
118
119 gv_check("fixture-reached-the-compiler-all-four-ran" as *u8, (rc_u >= 0) & (rc_m >= 0) & (rc_i >= 0) & (rc_d >= 0) & (rc_u != 127) & (rc_m != 127) & (rc_i != 127) & (rc_d != 127), c)
120 gv_check("unmarked-struct-across-the-pool-is-refused" as *u8, rc_u != 0, c)
121 gv_check("refusal-names-the-struct" as *u8, sg_find(eu, nu, "struct 'Job' is handed to another thread here, and it is not marked send" as *u8) >= 0, c)
122 gv_check("refusal-carries-the-location-anchor" as *u8, sg_find(eu, nu, "error at " as *u8) >= 0, c)
123 gv_check("refusal-carries-why-the-build-stopped" as *u8, sg_find(eu, nu, "why the build stopped" as *u8) >= 0, c)
124 gv_check("refusal-fix-shows-the-marker" as *u8, sg_find(eu, nu, "struct Job send { ... }" as *u8) >= 0, c)
125 gv_check("refusal-writes-no-program" as *u8, sg_find(eu, nu, "wrote no program" as *u8) >= 0, c)
126 gv_check("control-marked-send-compiles-exit-0" as *u8, rc_m == 0, c)
127 gv_check("control-marked-send-prints-no-refusal" as *u8, sg_find(em, nm, "not marked send" as *u8) < 0, c)
128 gv_check("control-plain-integer-ctx-is-abstained-exit-0" as *u8, rc_i == 0, c)
129 gv_check("neg-control-default-build-unchanged-exit-0" as *u8, rc_d == 0, c)
130 gv_check("neg-control-default-build-prints-no-refusal" as *u8, sg_find(ed, nd, "not marked send" as *u8) < 0, c)
131 return gv_verdict("SENDCHECK-GATE" as *u8, c, "LN6: under --sendcheck an unmarked struct handed to nx_pool_submit is refused by name; a struct marked send, a plain integer, and the default build all compile" as *u8)
132}