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}