code wiki / (root) / nx_sendcheck_gate.nx

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}