code wiki / _hdl_build / nx_diff_gen.nx
nx_diff_gen.nx source
↩ module page · 311 lines · 11029 B
1// nx_diff_gen.nx -- R1-T1-001: the differential-testing CORPUS GENERATOR
2// (the PREVENT instrument for the miscompile class; spec arc T1). Emits N
3// deterministic random programs in the SUPPORTED dialect envelope, so any
4// build/run failure is a NEW toolchain bug by construction, never a known
5// landmine:
6// counted while loops only (literal bound <=10 -> termination by
7// construction); ifs <=2 deep; i64 + - * only (no division); every shift
8// masked (LM-005); literals non-negative (LM-004); sys_exit((sum)&1) so
9// legal exits are EXACTLY {0,1} -- lane rc 3/4 = toolchain fail, >128 =
10// crash, anything else loud.
11// DETERMINISM: same conf (knowledge/registry/diff_corpus.conf: n/seed/
12// max_stmts) = byte-identical corpus (LCG PRNG, no time, no env) -- proven
13// by the gate via corpus-hash equality across runs. Programs land in
14// runtime/_hdl_build/<prefix><i>.nx because expand_imports resolves only
15// there (probed 2026-06-11: /tmp sources fail expand_imports) -- which also
16// means the DURABLE LANE builds any corpus program by basename, retry guard
17// included. Every file is PADDED to a fixed 3072 bytes with trailing
18// newlines: rewrites always cover prior content (LM-022 stale-tail killer
19// even across seed changes).
20// argv[1]=conf override argv[2]=name-prefix override (default _dgp)
21// argv[3]=hash-file override (default /tmp/_dg_hash.txt)
22// Evidence: DIFFGEN row -> stdout + knowledge/status/diff_gen.log.
23// license_tier: ORIGINAL
24
25import "nx_syscalls.nx"
26import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
27const DG_MAGIC_1103515245: i64 = 1103515245
28const DG_MAGIC_12345: i64 = 12345
29const DG_MAGIC_2800: i64 = 2800
30const DG_MAGIC_4096: i64 = 4096
31const DG_MAGIC_4095: i64 = 4095
32const DG_MAGIC_1106202601: i64 = 1106202601
33const DG_MAGIC_1469598103: i64 = 1469598103
34
35const DG_FILEPAD: i64 = 3072
36const DG_BUFCAP: i64 = 4096
37
38func dg_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
39func dg_fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
40// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
41// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
42// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
43// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
44func dg_fn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
45
46func dg_cat(dst: *u8, off: i64, s: *u8) -> i64 {
47 var i: i64 = 0
48 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
49 return off + i
50}
51
52func dg_catn(dst: *u8, off: i64, v: i64) -> i64 {
53 var m: i64 = v
54 if m < 0 { m = 0 }
55 let t: *u8 = sys_mmap(28)
56 var k: i64 = 0
57 if m == 0 { t[0] = 48 as u8; k = 1 }
58 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
59 var o: i64 = off
60 var i: i64 = 0
61 while i < k { dst[o] = t[k - 1 - i]; o = o + 1; i = i + 1 }
62 return o
63}
64
65// classic LCG, 31-bit state: deterministic, overflow-free
66func dg_rnd(st: *i64, k: i64) -> i64 {
67 st[0] = (st[0] * DG_MAGIC_1103515245 + DG_MAGIC_12345) & 0x7fffffff
68 return (st[0] >> 16) % k
69}
70
71// append "v<idx>" (idx 0..3)
72func dg_catv(dst: *u8, off: i64, idx: i64) -> i64 {
73 dst[off] = 118 as u8
74 dst[off + 1] = (48 + idx) as u8
75 return off + 2
76}
77
78// one straight-line arithmetic statement
79func dg_st_arith(b: *u8, off: i64, st: *i64) -> i64 {
80 let a: i64 = dg_rnd(st, 4)
81 let c: i64 = dg_rnd(st, 4)
82 let kind: i64 = dg_rnd(st, 4)
83 var o: i64 = dg_cat(b, off, " " as *u8)
84 o = dg_catv(b, o, a)
85 o = dg_cat(b, o, " = " as *u8)
86 if kind == 0 {
87 o = dg_catv(b, o, a)
88 o = dg_cat(b, o, " + " as *u8)
89 o = dg_catv(b, o, c)
90 }
91 if kind == 1 {
92 o = dg_catv(b, o, a)
93 o = dg_cat(b, o, " * 3 + " as *u8)
94 o = dg_catn(b, o, dg_rnd(st, 17))
95 }
96 if kind == 2 {
97 o = dg_cat(b, o, "(" as *u8)
98 o = dg_catv(b, o, a)
99 o = dg_cat(b, o, " >> " as *u8)
100 o = dg_catn(b, o, 1 + dg_rnd(st, 5))
101 o = dg_cat(b, o, ") & 0xffff" as *u8)
102 }
103 if kind == 3 {
104 o = dg_cat(b, o, "(" as *u8)
105 o = dg_catv(b, o, a)
106 o = dg_cat(b, o, " << " as *u8)
107 o = dg_catn(b, o, 1 + dg_rnd(st, 3))
108 o = dg_cat(b, o, ") & 0xfffffff" as *u8)
109 }
110 o = dg_cat(b, o, "\n" as *u8)
111 return o
112}
113
114// if / if-else / 2-deep if
115func dg_st_branch(b: *u8, off: i64, st: *i64) -> i64 {
116 let a: i64 = dg_rnd(st, 4)
117 let c: i64 = dg_rnd(st, 4)
118 let d: i64 = dg_rnd(st, 4)
119 let kind: i64 = dg_rnd(st, 2)
120 var o: i64 = dg_cat(b, off, " if " as *u8)
121 o = dg_catv(b, o, a)
122 o = dg_cat(b, o, " > " as *u8)
123 o = dg_catv(b, o, c)
124 o = dg_cat(b, o, " { " as *u8)
125 o = dg_catv(b, o, d)
126 o = dg_cat(b, o, " = " as *u8)
127 o = dg_catv(b, o, d)
128 o = dg_cat(b, o, " + 1 }" as *u8)
129 if kind == 1 {
130 o = dg_cat(b, o, " else { " as *u8)
131 o = dg_catv(b, o, d)
132 o = dg_cat(b, o, " = " as *u8)
133 o = dg_catv(b, o, d)
134 o = dg_cat(b, o, " - 1 }" as *u8)
135 }
136 o = dg_cat(b, o, "\n" as *u8)
137 return o
138}
139
140// counted loop: termination by construction (literal bound)
141func dg_st_loop(b: *u8, off: i64, st: *i64, sidx: i64) -> i64 {
142 let a: i64 = dg_rnd(st, 4)
143 let bound: i64 = 2 + dg_rnd(st, 9)
144 var o: i64 = dg_cat(b, off, " var i" as *u8)
145 o = dg_catn(b, o, sidx)
146 o = dg_cat(b, o, ": i64 = 0\n while i" as *u8)
147 o = dg_catn(b, o, sidx)
148 o = dg_cat(b, o, " < " as *u8)
149 o = dg_catn(b, o, bound)
150 o = dg_cat(b, o, " { " as *u8)
151 o = dg_catv(b, o, a)
152 o = dg_cat(b, o, " = " as *u8)
153 o = dg_catv(b, o, a)
154 o = dg_cat(b, o, " + 2; i" as *u8)
155 o = dg_catn(b, o, sidx)
156 o = dg_cat(b, o, " = i" as *u8)
157 o = dg_catn(b, o, sidx)
158 o = dg_cat(b, o, " + 1 }\n" as *u8)
159 return o
160}
161
162// whole program text into b; returns length
163func dg_program(b: *u8, st: *i64, idx: i64, max_stmts: i64) -> i64 {
164 var o: i64 = dg_cat(b, 0, "// generated corpus program idx=" as *u8)
165 o = dg_catn(b, o, idx)
166 o = dg_cat(b, o, " (nx_diff_gen, deterministic)\nimport \"nx_syscalls.nx\"\nfunc main() -> i64 {\n" as *u8)
167 var v: i64 = 0
168 while v < 4 {
169 o = dg_cat(b, o, " var " as *u8)
170 o = dg_catv(b, o, v)
171 o = dg_cat(b, o, ": i64 = " as *u8)
172 o = dg_catn(b, o, dg_rnd(st, 100))
173 o = dg_cat(b, o, "\n" as *u8)
174 v = v + 1
175 }
176 var span: i64 = max_stmts - 3
177 if span < 1 { span = 1 }
178 let nst: i64 = 4 + dg_rnd(st, span)
179 var s: i64 = 0
180 while s < nst {
181 let kind: i64 = dg_rnd(st, 4)
182 if kind <= 1 { o = dg_st_arith(b, o, st) }
183 if kind == 2 { o = dg_st_branch(b, o, st) }
184 if kind == 3 { o = dg_st_loop(b, o, st, s) }
185 s = s + 1
186 if o > DG_MAGIC_2800 { s = nst }
187 }
188 o = dg_cat(b, o, " sys_exit((((v0 + v1) + v2) + v3) & 1)\n return 0\n}\n" as *u8)
189 return o
190}
191
192// write program file padded to DG_FILEPAD bytes (stale-tail killer)
193func dg_write(path: *u8, b: *u8, len: i64) -> i64 {
194 var o: i64 = len
195 while o < DG_FILEPAD { b[o] = 10 as u8; o = o + 1 }
196 let fd: i64 = sys_openat_wr(path, 0x1a4)
197 if fd < 0 { return 0 }
198 var off: i64 = 0
199 while off < DG_FILEPAD {
200 let w: i64 = sys_write(fd, b + off, DG_FILEPAD - off)
201 if w <= 0 { sys_close(fd); return 0 }
202 off = off + w
203 }
204 sys_close(fd)
205 return 1
206}
207
208// conf key=N reader (wd_conf_deadline shape, shared scan)
209func dg_conf(buf: *u8, n: i64, key: *u8, kl: i64, dflt: i64) -> i64 {
210 var i: i64 = 0
211 var at: i64 = 0 - 1
212 while i < n {
213 if i + kl <= n {
214 var k: i64 = 0
215 var hit: i64 = 1
216 while k < kl {
217 if buf[i + k] != key[k] { hit = 0; k = kl } else { k = k + 1 }
218 }
219 if hit == 1 { at = i + kl; i = n }
220 }
221 i = i + 1
222 }
223 if at < 0 { return dflt }
224 var v: i64 = 0
225 var any: i64 = 0
226 var go: i64 = 1
227 while go == 1 {
228 if at >= n { go = 0 } else {
229 let ch: i64 = buf[at] as i64
230 if ch >= 48 {
231 if ch <= 57 { v = v * 10 + (ch - 48); any = 1; at = at + 1 } else { go = 0 }
232 } else { go = 0 }
233 }
234 }
235 if any == 0 { return dflt }
236 return v
237}
238
239func main(argc: i64, argv: *i64) -> i64 {
240 var confp: *u8 = "knowledge/registry/diff_corpus.conf" as *u8
241 var prefix: *u8 = "_dgp" as *u8
242 var hashp: *u8 = "/tmp/_dg_hash.txt" as *u8
243 if argc >= 2 { confp = argv[1] as *u8 }
244 if argc >= 3 { prefix = argv[2] as *u8 }
245 if argc >= 4 { hashp = argv[3] as *u8 }
246
247 let cbuf: *u8 = sys_mmap(DG_MAGIC_4096)
248 var cn: i64 = 0
249 let cfd: i64 = sys_openat_rd(confp)
250 if cfd >= 0 {
251 var r: i64 = sys_read(cfd, cbuf, DG_MAGIC_4095)
252 while r > 0 { cn = cn + r; r = sys_read(cfd, cbuf + cn, DG_MAGIC_4095 - cn) }
253 sys_close(cfd)
254 }
255 let n: i64 = dg_conf(cbuf, cn, "n=" as *u8, 2, 200)
256 let seed: i64 = dg_conf(cbuf, cn, "seed=" as *u8, 5, DG_MAGIC_1106202601)
257 let mx: i64 = dg_conf(cbuf, cn, "max_stmts=" as *u8, 10, 12)
258
259 let st: *i64 = sys_mmap(16) as *i64
260 st[0] = seed & 0x7fffffff
261 let b: *u8 = sys_mmap(DG_BUFCAP)
262 let path: *u8 = sys_mmap(256)
263 var hash: i64 = DG_MAGIC_1469598103
264 var total: i64 = 0
265 var wrote: i64 = 0
266 var i: i64 = 0
267 while i < n {
268 let len: i64 = dg_program(b, st, i, mx)
269 var po: i64 = dg_cat(path, 0, "runtime/_hdl_build/" as *u8)
270 po = dg_cat(path, po, prefix)
271 po = dg_catn(path, po, i)
272 po = dg_cat(path, po, ".nx" as *u8)
273 path[po] = 0 as u8
274 if dg_write(path, b, len) == 1 { wrote = wrote + 1 }
275 var h: i64 = 0
276 while h < DG_FILEPAD { hash = (hash * 131 + (b[h] as i64)) & 0x7fffffffffff; h = h + 1 }
277 total = total + len
278 i = i + 1
279 }
280
281 let hf: i64 = sys_openat_wr(hashp, 0x1a4)
282 if hf >= 0 {
283 dg_fn(hf, hash)
284 dg_fp(hf, " \n" as *u8)
285 sys_close(hf)
286 }
287
288 let lfd: i64 = sys_openat_append("knowledge/status/diff_gen.log" as *u8, 0x1a4)
289 var verdict: *u8 = "GREEN" as *u8
290 var rc: i64 = 0
291 if wrote != n { verdict = "RED" as *u8; rc = 1 }
292 var p2: i64 = 0
293 while p2 < 2 {
294 var fd: i64 = 1
295 if p2 == 1 { fd = lfd }
296 if fd >= 0 {
297 dg_fp(fd, "DIFFGEN n=" as *u8); dg_fn(fd, n)
298 dg_fp(fd, " wrote=" as *u8); dg_fn(fd, wrote)
299 dg_fp(fd, " seed=" as *u8); dg_fn(fd, seed)
300 dg_fp(fd, " hash=" as *u8); dg_fn(fd, hash)
301 dg_fp(fd, " bytes=" as *u8); dg_fn(fd, total)
302 dg_fp(fd, " epoch=" as *u8); dg_fn(fd, sys_now_realtime_sec())
303 dg_fp(fd, " verdict=" as *u8); dg_fp(fd, verdict)
304 dg_fp(fd, "\n" as *u8)
305 }
306 p2 = p2 + 1
307 }
308 if lfd >= 0 { sys_close(lfd) }
309 sys_exit(rc)
310 return rc
311}