code wiki / _hdl_build / nx_fwdconst_scan.nx

nx_fwdconst_scan.nx source

↩ module page · 255 lines · 9467 B

1// nx_fwdconst_scan.nx -- FORWARD-CONST DEAD-READ DETECTOR (eats seq360's discovery half, 2026-07-20). 2// The miscompile class: a module const READ by code textually ABOVE its declaration resolves to 3// CONSTANT 0 in binaries built before the 07-20 nx_cc diagnostic (proven live: AT_FDCWD dirfd=0, 4// VC_EO_PART/VC_EO_T8 codec early-outs dead since 07-12). The new compiler REJECTS the pattern at 5// build time; this organ finds it in SOURCE so already-shipped binaries' sources get fixed+rebuilt 6// deliberately, and the class is sweepable on cadence forever. 7// argv: <dir> [dir2] [dir3] (flat dirs, .nx files; the build-resolution pair is the usual input) 8// Report rows: FWDCONST <file> use-line=<L> const=<NAME> decl-line=<D> 9// Summary: NX-FWDCONST-SCAN files=<f> consts=<c> flagged=<n> skipped-big=<s> (exit 0 = scan completed) 10// HONEST SCOPE v1: full-comment lines (// or \) and double-quoted spans are SKIPPED; an INLINE 11// trailing comment mentioning the name still flags (rare; review rows by eye). Reporter only -- 12// a ratchet gate asserting flagged<=N composes on top once the map is eaten. 13// license_tier: ORIGINAL No hw writes (Rule 26). 14import "nx_sovjson_lib.nx" 15import "nx_syscalls.nx" 16const FW_MAGIC_4096: i64 = 4096 17const FW_MAGIC_262144: i64 = 262144 18 19const FW_FILE_CAP: i64 = 2097152 20const FW_NAME_CAP: i64 = 64 21const FW_MAX_CONSTS: i64 = 512 22 23static g_names: *u8 24static g_doffs: *i64 25 26func fw_w(s: *u8) -> i64 { return sj_puts(s) } 27 28func fw_wn(v: i64) -> i64 { 29 var t: i64 = v 30 if t < 0 { sys_write(1, "-" as *u8, 1); t = 0 - t } 31 let tm: *u8 = sys_mmap(24) 32 var k: i64 = 0 33 if t == 0 { tm[0] = 48 as u8; k = 1 } 34 while t > 0 { tm[k] = (48 + (t % 10)) as u8; t = t / 10; k = k + 1 } 35 let b: *u8 = sys_mmap(24) 36 var j: i64 = 0 37 while j < k { b[j] = tm[k - 1 - j]; j = j + 1 } 38 sys_write(1, b, k) 39 return 0 40} 41 42func fw_isid(c: i64) -> i64 { 43 if c >= 97 { if c <= 122 { return 1 } } 44 if c >= 65 { if c <= 90 { return 1 } } 45 if c >= 48 { if c <= 57 { return 1 } } 46 if c == 95 { return 1 } 47 return 0 48} 49 50func fw_read(path: *u8, buf: *u8, cap: i64) -> i64 { 51 let fd: i64 = sys_openat_rd(path) 52 if fd < 0 { return 0 - 1 } 53 var n: i64 = 0 54 var r: i64 = sys_read(fd, buf, cap - 1) 55 while r > 0 { n = n + r; if n >= cap - 1 { r = 0 } else { r = sys_read(fd, buf + n, cap - 1 - n) } } 56 sys_close(fd) 57 return n 58} 59 60func fw_line_of(buf: *u8, off: i64) -> i64 { 61 var ln: i64 = 1 62 var i: i64 = 0 63 while i < off { if buf[i] == (10 as u8) { ln = ln + 1 } i = i + 1 } 64 return ln 65} 66 67func ends_nx2(nm: *u8) -> i64 { 68 var n: i64 = 0 69 while nm[n] != (0 as u8) { n = n + 1 } 70 if n < 3 { return 0 } 71 if nm[n-3] == (46 as u8) { if nm[n-2] == (110 as u8) { if nm[n-1] == (120 as u8) { return 1 } } } 72 return 0 73} 74 75func join2(buf: *u8, dir: *u8, name: *u8) -> i64 { 76 var o: i64 = 0 77 var i: i64 = 0 78 while dir[i] != (0 as u8) { buf[o] = dir[i]; o = o + 1; i = i + 1 } 79 buf[o] = 47 as u8 80 o = o + 1 81 i = 0 82 while name[i] != (0 as u8) { buf[o] = name[i]; o = o + 1; i = i + 1 } 83 buf[o] = 0 as u8 84 return 0 85} 86 87// pass A: collect module const decls "const NAME" at line starts into g_names/g_doffs; returns count 88func fw_collect(buf: *u8, n: i64) -> i64 { 89 var cnt: i64 = 0 90 var ls: i64 = 0 91 while ls < n { 92 var p: i64 = ls 93 // "const " at line start (col 0 -- module consts in this codebase) 94 var m: i64 = 1 95 if p + 6 >= n { m = 0 } 96 if m == 1 { if buf[p] != (99 as u8) { m = 0 } } 97 if m == 1 { if buf[p+1] != (111 as u8) { m = 0 } } 98 if m == 1 { if buf[p+2] != (110 as u8) { m = 0 } } 99 if m == 1 { if buf[p+3] != (115 as u8) { m = 0 } } 100 if m == 1 { if buf[p+4] != (116 as u8) { m = 0 } } 101 if m == 1 { if buf[p+5] != (32 as u8) { m = 0 } } 102 if m == 1 { 103 var q: i64 = p + 6 104 while buf[q] == (32 as u8) { q = q + 1 } 105 var e: i64 = q 106 var run: i64 = 1 107 while run == 1 { 108 if e >= n { run = 0 } else { let c: i64 = buf[e] as i64; if fw_isid(c) == 1 { e = e + 1 } else { run = 0 } } 109 } 110 let nl: i64 = e - q 111 if nl > 0 { if nl < FW_NAME_CAP - 1 { if cnt < FW_MAX_CONSTS { 112 let slot: *u8 = ((g_names as i64) + cnt * FW_NAME_CAP) as *u8 113 var w: i64 = 0 114 while w < nl { slot[w] = buf[q + w]; w = w + 1 } 115 slot[nl] = 0 as u8 116 let dof: *i64 = g_doffs 117 dof[cnt] = ls 118 cnt = cnt + 1 119 } } } 120 } 121 var adv: i64 = 1 122 while adv == 1 { 123 if ls >= n { adv = 0 } else { let c2: i64 = buf[ls] as i64; ls = ls + 1; if c2 == 10 { adv = 0 } } 124 } 125 } 126 return cnt 127} 128 129// pass B: first word-boundary use of name in buf[0..limit), skipping comment lines + quoted spans. 130// returns byte offset of the hit or -1. 131func fw_first_use(buf: *u8, limit: i64, name: *u8) -> i64 { 132 var nl: i64 = 0 133 while name[nl] != (0 as u8) { nl = nl + 1 } 134 var p: i64 = 0 135 var linestart: i64 = 1 136 var incmt: i64 = 0 137 var inq: i64 = 0 138 while p < limit { 139 let c: i64 = buf[p] as i64 140 if c == 10 { linestart = 1; incmt = 0; inq = 0; p = p + 1 } else { 141 if linestart == 1 { 142 var sp: i64 = p 143 while buf[sp] == (32 as u8) { sp = sp + 1 } 144 if buf[sp] == (92 as u8) { incmt = 1 } 145 if buf[sp] == (47 as u8) { if buf[sp+1] == (47 as u8) { incmt = 1 } } 146 linestart = 0 147 } 148 if incmt == 1 { p = p + 1 } else { 149 if c == 34 { inq = 1 - inq; p = p + 1 } else { 150 if inq == 1 { p = p + 1 } else { 151 var hit: i64 = 1 152 if p + nl > limit { hit = 0 } 153 var k: i64 = 0 154 var chk: i64 = 1 155 while chk == 1 { 156 if hit == 0 { chk = 0 } else { 157 if k >= nl { chk = 0 } else { 158 if buf[p + k] != name[k] { hit = 0; chk = 0 } else { k = k + 1 } 159 } 160 } 161 } 162 if hit == 1 { 163 var pb: i64 = 0 164 if p > 0 { pb = fw_isid(buf[p-1] as i64) } 165 var nb: i64 = 0 166 if p + nl < limit { nb = fw_isid(buf[p+nl] as i64) } 167 if pb == 0 { if nb == 0 { return p } } 168 } 169 p = p + 1 170 } 171 } 172 } 173 } 174 } 175 return 0 - 1 176} 177 178// scan one file; prints FWDCONST rows; returns flags found 179func fw_process(path: *u8, buf: *u8) -> i64 { 180 let n: i64 = fw_read(path, buf, FW_FILE_CAP) 181 if n <= 0 { return 0 } 182 let nc: i64 = fw_collect(buf, n) 183 var flags: i64 = 0 184 var i: i64 = 0 185 while i < nc { 186 let nm: *u8 = ((g_names as i64) + i * FW_NAME_CAP) as *u8 187 let dof: *i64 = g_doffs 188 let dl: i64 = dof[i] 189 let hit: i64 = fw_first_use(buf, dl, nm) 190 if hit >= 0 { 191 fw_w("FWDCONST " as *u8) 192 fw_w(path) 193 fw_w(" use-line=" as *u8) 194 let ul: i64 = fw_line_of(buf, hit) 195 fw_wn(ul) 196 fw_w(" const=" as *u8) 197 fw_w(nm) 198 fw_w(" decl-line=" as *u8) 199 let dln: i64 = fw_line_of(buf, dl) 200 fw_wn(dln) 201 fw_w("\n" as *u8) 202 flags = flags + 1 203 } 204 i = i + 1 205 } 206 return flags 207} 208 209func main(argc: i64, argv: *i64) -> i64 { 210 if argc < 2 { fw_w("usage: nx_fwdconst_scan <dir> [dir2] [dir3]\n" as *u8); sys_exit(2); return 2 } 211 if (g_names as i64) == 0 { g_names = sys_mmap(FW_MAX_CONSTS * FW_NAME_CAP) } 212 if (g_doffs as i64) == 0 { g_doffs = sys_mmap(FW_MAX_CONSTS * 8) as *i64 } 213 let buf: *u8 = sys_mmap(FW_FILE_CAP) 214 let pbuf: *u8 = sys_mmap(FW_MAGIC_4096) 215 let dbuf: *u8 = sys_mmap(FW_MAGIC_262144) 216 var files: i64 = 0 217 var flagged: i64 = 0 218 var d: i64 = 1 219 while d < argc { 220 let dir: *u8 = argv[d] as *u8 221 let fd: i64 = sys_openat_rd(dir) 222 if fd >= 0 { 223 var go: i64 = 1 224 while go == 1 { 225 let nr: i64 = sys_getdents64(fd, dbuf, FW_MAGIC_262144) 226 if nr <= 0 { go = 0 } else { 227 var off: i64 = 0 228 while off < nr { 229 let rec: *u8 = ((dbuf as i64) + off) as *u8 230 let ty: i64 = dirent_type(rec) 231 let nm: *u8 = dirent_name(rec) 232 if ty != 4 { 233 if ends_nx2(nm) == 1 { 234 join2(pbuf, dir, nm) 235 files = files + 1 236 let fl: i64 = fw_process(pbuf, buf) 237 flagged = flagged + fl 238 } 239 } 240 off = off + dirent_reclen(rec) 241 } 242 } 243 } 244 sys_close(fd) 245 } 246 d = d + 1 247 } 248 fw_w("NX-FWDCONST-SCAN files=" as *u8) 249 fw_wn(files) 250 fw_w(" flagged=" as *u8) 251 fw_wn(flagged) 252 fw_w("\n" as *u8) 253 sys_exit(0) 254 return 0 255}