code wiki / _hdl_build / nx_constscan_beat.nx

nx_constscan_beat.nx source

↩ module page · 279 lines · 9611 B

1// nx_constscan_beat.nx -- STANDING guard for LM-030, the const-pointer direct-index SILENT MISCOMPILE. 2// 3// WHY A BEAT: on 2026-07-30 I reproduced LM-030 with a controlled probe/control pair -- CONST[i] compiles 4// clean, runs, and returns WRONG DATA with no diagnostic anywhere -- then scanned all 17,501 .nx in the tree 5// and found hits=0. Clean TODAY is not a property; it is a snapshot. A defect whose only symptom is a wrong 6// number needs a continuous guard, because the first reintroduction is invisible by construction. 7// 8// WHY THE DETECTOR WAS DARK, which is the real lesson: nx_doc_constscan already existed and had even measured 9// the same garbage value, but it was SOURCE-ONLY -- never built, never in tool_allowlist.conf, never on the 10// sweep rail. A detector nobody can run is not a guard. This beat is the missing rail. 11// 12// Discovers + batches + aggregates ONLY. It forks the proven ./nx_doc_constscan_run.elf exactly as 13// nx_store_fold_beat forks nx_store_compact, so the DETECTOR keeps sole ownership of what counts as a hit. 14// Batching exists because the runner takes files as argv and the tree is ~17.5k files -- one exec cannot hold 15// them, so this is xargs-in-an-organ, not a re-implementation. 16// 17// Sweep-row contract: exit 0 = zero LM-030 sites; exit 1 = at least one, surfaced RED with the count. 18// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 19import "nx_syscalls.nx" 20import "nx_tool_run.nx" 21 22const CB_DIRBUF: i64 = 262144 23const CB_ARENA: i64 = 1048576 24const CB_OUTCAP: i64 = 262144 25const CB_PATHCAP: i64 = 1024 26const CB_BATCH: i64 = 96 27const CB_AVSLOTS: i64 = 100 28const CB_STDOUT: i64 = 1 29const CB_NL: i64 = 10 30 31func cb_len(s: *u8) -> i64 { 32 var n: i64 = 0 33 while s[n] != (0 as u8) { 34 n = n + 1 35 } 36 return n 37} 38func cb_puts(s: *u8) -> i64 { 39 sys_write(CB_STDOUT, s, cb_len(s)) 40 return 0 41} 42func cb_putn(v: i64) -> i64 { 43 let t: *u8 = sys_mmap(32) 44 let b: *u8 = sys_mmap(32) 45 var m: i64 = v 46 if m < 0 { 47 m = 0 - m 48 } 49 var k: i64 = 0 50 if m == 0 { 51 t[0] = 48 as u8 52 k = 1 53 } 54 while m > 0 { 55 t[k] = (48 + (m % 10)) as u8 56 m = m / 10 57 k = k + 1 58 } 59 var i: i64 = 0 60 while i < k { 61 b[i] = t[k - 1 - i] 62 i = i + 1 63 } 64 sys_write(CB_STDOUT, b, k) 65 sys_munmap(t, 32) 66 sys_munmap(b, 32) 67 return 0 68} 69// name ends in .nx and is not a shadow copy (.migrated/.premigrate/.bak/.retired/MOVED/SHADOW) 70// FIXTURE EXCLUSION (2026-07-30). Two files in the tree contain LM-030 ON PURPOSE and must not turn a 71// standing guard RED forever: nx_constidx_probe.nx is the positive control that PROVES the detector can fire 72// (its safe twin nx_constidx_ctrl.nx must stay clean), and nx_doc_constscan_gate.nx carries KAT fixture 73// STRINGS containing the offending pattern as test input. Excluding a deliberate fixture is what lint 74// exclusions are for; excluding it is NOT the same as suppressing a finding, and the exclusion is BY NAME so 75// a real defect anywhere else still fires. ⚠RESIDUAL, filed not hidden: cs_scan skips // comments but NOT 76// string literals, which is why the gate's fixture strings match at all -- root fix is a string-literal skip. 77func cb_is_fixture(nm: *u8) -> i64 { 78 let a: *u8 = "nx_constidx_probe.nx" as *u8 79 let b: *u8 = "nx_doc_constscan_gate.nx" as *u8 80 var i: i64 = 0 81 var same: i64 = 1 82 while a[i] != (0 as u8) { 83 if nm[i] != a[i] { same = 0 } 84 i = i + 1 85 } 86 if same == 1 { if nm[i] == (0 as u8) { return 1 } } 87 var j: i64 = 0 88 var same2: i64 = 1 89 while b[j] != (0 as u8) { 90 if nm[j] != b[j] { same2 = 0 } 91 j = j + 1 92 } 93 if same2 == 1 { if nm[j] == (0 as u8) { return 1 } } 94 return 0 95} 96func cb_is_scannable(nm: *u8) -> i64 { 97 let n: i64 = cb_len(nm) 98 if n < 4 { 99 return 0 100 } 101 if cb_is_fixture(nm) == 1 { 102 return 0 103 } 104 if nm[n - 3] != (46 as u8) { 105 return 0 106 } 107 if nm[n - 2] != (110 as u8) { 108 return 0 109 } 110 if nm[n - 1] != (120 as u8) { 111 return 0 112 } 113 return 1 114} 115// sum every "hits=N" the runner printed in this batch 116func cb_hits(buf: *u8, n: i64) -> i64 { 117 let key: *u8 = "hits=" as *u8 118 let kl: i64 = 5 119 var total: i64 = 0 120 var i: i64 = 0 121 while i + kl < n { 122 var ok: i64 = 1 123 var k: i64 = 0 124 while k < kl { 125 if buf[i + k] != key[k] { 126 ok = 0 127 k = kl 128 } else { 129 k = k + 1 130 } 131 } 132 if ok == 1 { 133 var v: i64 = 0 134 var j: i64 = i + kl 135 var go: i64 = 1 136 while go == 1 { 137 if j >= n { 138 go = 0 139 } else { 140 let c: i64 = buf[j] 141 var d: i64 = 0 142 if c >= 48 { 143 if c <= 57 { 144 d = 1 145 } 146 } 147 if d == 1 { 148 v = v * 10 + (c - 48) 149 j = j + 1 150 } else { 151 go = 0 152 } 153 } 154 } 155 total = total + v 156 i = j 157 } else { 158 i = i + 1 159 } 160 } 161 return total 162} 163 164func main(argc: i64, argv: *i64) -> i64 { 165 let runner: *u8 = "./nx_doc_constscan_run.elf" as *u8 166 let dbuf: *u8 = sys_mmap(CB_DIRBUF) 167 let arena: *u8 = sys_mmap(CB_ARENA) 168 let av: *i64 = sys_mmap(8 * CB_AVSLOTS) as *i64 169 let out: *u8 = sys_mmap(CB_OUTCAP) 170 let ol: *i64 = sys_mmap(16) as *i64 171 var scanned: i64 = 0 172 var hits: i64 = 0 173 var batches: i64 = 0 174 var failed: i64 = 0 175 176 var d: i64 = 0 177 while d < 2 { 178 var dir: *u8 = "buildroot/runtime" as *u8 179 if d == 1 { 180 dir = "buildroot/runtime/_hdl_build" as *u8 181 } 182 let dl: i64 = cb_len(dir) 183 let fd: i64 = sys_openat_rd(dir) 184 if fd < 0 { 185 cb_puts("CONSTSCAN-BEAT RED cannot open " as *u8) 186 cb_puts(dir) 187 cb_puts("\n" as *u8) 188 return 1 189 } 190 var ao: i64 = 0 191 var nb_in: i64 = 0 192 av[0] = runner as i64 193 var go: i64 = 1 194 while go == 1 { 195 let nb: i64 = sys_getdents64(fd, dbuf, CB_DIRBUF) 196 if nb <= 0 { 197 go = 0 198 } else { 199 var off: i64 = 0 200 while off < nb { 201 let rec: *u8 = (dbuf as i64 + off) as *u8 202 let rl: i64 = dirent_reclen(rec) 203 if rl <= 0 { 204 off = nb 205 } else { 206 let nm: *u8 = dirent_name(rec) 207 if cb_is_scannable(nm) == 1 { 208 let want: i64 = ao + dl + cb_len(nm) + 2 209 if want < CB_ARENA { 210 let start: i64 = ao 211 var z: i64 = 0 212 while z < dl { 213 arena[ao] = dir[z] 214 ao = ao + 1 215 z = z + 1 216 } 217 arena[ao] = 47 as u8 218 ao = ao + 1 219 var y: i64 = 0 220 while nm[y] != (0 as u8) { 221 arena[ao] = nm[y] 222 ao = ao + 1 223 y = y + 1 224 } 225 arena[ao] = 0 as u8 226 ao = ao + 1 227 nb_in = nb_in + 1 228 av[nb_in] = (arena as i64) + start 229 scanned = scanned + 1 230 if nb_in >= CB_BATCH { 231 av[nb_in + 1] = 0 232 let rc: i64 = tr_run_capture(runner, av, out, CB_OUTCAP - 1, ol) 233 if rc != 0 { 234 failed = failed + 1 235 } 236 hits = hits + cb_hits(out, ol[0]) 237 batches = batches + 1 238 nb_in = 0 239 ao = 0 240 } 241 } 242 } 243 off = off + rl 244 } 245 } 246 } 247 } 248 sys_close(fd) 249 if nb_in > 0 { 250 av[nb_in + 1] = 0 251 let rc2: i64 = tr_run_capture(runner, av, out, CB_OUTCAP - 1, ol) 252 if rc2 != 0 { 253 failed = failed + 1 254 } 255 hits = hits + cb_hits(out, ol[0]) 256 batches = batches + 1 257 } 258 d = d + 1 259 } 260 261 cb_puts("CONSTSCAN-BEAT scanned=" as *u8) 262 cb_putn(scanned) 263 cb_puts(" batches=" as *u8) 264 cb_putn(batches) 265 cb_puts(" batch_failures=" as *u8) 266 cb_putn(failed) 267 cb_puts(" LM030_hits=" as *u8) 268 cb_putn(hits) 269 if hits > 0 { 270 cb_puts(" verdict=RED-const-pointer-indexed-directly-SILENT-MISCOMPILE-bind-to-a-local-let\n" as *u8) 271 return 1 272 } 273 if failed > 0 { 274 cb_puts(" verdict=RED-a-batch-FAILED-coverage-incomplete-do-not-read-hits-as-zero\n" as *u8) 275 return 1 276 } 277 cb_puts(" verdict=GREEN-no-LM-030-sites\n" as *u8) 278 return 0 279}