nx_autofix_lib.nx source
↩ module page · 1005 lines · 49846 B
1// nx_autofix_lib.nx -- THE SHARED RULERS OF THE AUTONOMOUS FIX LOOP (autodev M0, 2026-08-27).
2//
3// WHY A LIB: nx_autofix_auto (the loop), nx_autofix_intake_gate (the intake) and nx_swebench_local_gate
4// (the judge) each carried their own copy of "find the failing FNRES row", their own ledger path
5// literal (/home/elderwesto/nx_stage/...) and their own idea of what a proposal row means. Three
6// organs that must agree cannot be kept agreeing by discipline; only one copy holds. This is the
7// one copy, and the contract symbols on the /compare/autodev board (af_episode_ledger,
8// af_sandbox_root, af_null_control, af_admit_untrusted, af_intake_board) are thin composers over it in
9// nx_autofix_auto.nx -- the loop's call sites -- while the gates drive these rulers in-process.
10//
11// THE FIVE RULERS
12// AD5 EPISODE LEDGER afl_ledger_* -- one row per episode, appended AS DECIDED to an estate-relative
13// journal (knowledge/status/autofix_ledger.jrnl) so a run interrupted at 95 percent
14// keeps 95 percent, and the page reads the plane and nothing else. The dev-box
15// stage ledger stays the fallback (nx_stage_path), never a literal.
16// AD7 SANDBOX ROOT afl_sandbox_* -- every candidate builds and runs in /tmp/afx_sb_<ts>_<name>/
17// with its import closure COPIED (not linked: a write through a link would reach
18// the tree), the toolchain linked read-only, a real _build/, RLIMIT_CPU and
19// RLIMIT_AS on the child, a wall deadline that kills the whole process group.
20// The tree copy is never opened for write; afl_bytes_eq is the witness.
21// AD4 NULL CONTROLS afl_null_controls -- the empty patch and a replay of a prior solution are run
22// through the SAME judge; a null that scores GREEN is an oracle defect and the
23// batch is REFUSED, never published. Echo is rejected pre-verify by byte identity
24// (structural) and the revert patch is the empty patch by construction; both are
25// named on the line rather than counted twice.
26// AD6 UNTRUSTED INPUT afl_admit_row -- deny by default: a proposal row is LOCAL (built and run in the
27// sandbox) or EXTERNAL DATA-ONLY (provenance-pinned h<sha> AND maintainer-merged,
28// never executed); an external row missing either is refused BY NAME.
29// AD3 INTAKE PLANE afl_intake_emit -- folds the estate's own boards into one task plane: roster
30// RED gates, the adjudicated drift worklist, the magic ratchet counts, the unwired
31// baseline; every task carries its oracle and a RED-before receipt; the partition
32// prints its sum; debt rows carry no executable oracle and are REFUSED as
33// UNREPRODUCED (counted, never hidden); a source that is absent says ABSENT-SOURCE.
34//
35// CONF (rule 17: env > conf > bootstrap): knowledge/autofix.conf rows sandbox_wall_ms, sandbox_as_bytes,
36// bon_n, bon_temp_pm, bon_topp_pm, bon_topk, null_controls_max_green. The defaults below are the July
37// contract values with the reason each was chosen written beside it.
38// license_tier: ORIGINAL No hw writes (Rule 26).
39import "nx_syscalls.nx"
40import "nx_estate_path.nx"
41import "nx_stage_path.nx"
42import "nx_tool_run.nx"
43
44const AFL_PATH: i64 = 4096 // Linux PATH_MAX, the same bound nx_stage_path uses
45const AFL_LINE: i64 = 2048
46const AFL_NAME: i64 = 64
47const AFL_HARNESS: i64 = 128
48const AFL_MODE_0644: i64 = 420
49const AFL_MODE_0755: i64 = 493
50const AFL_ABSENT: i64 = 0 - 999999
51const AFL_CAPTURE: i64 = 1048576 // one grader capture; the July candidates print under 1 KB, the bound announces when it binds
52const AFL_LEDGER_JRNL: *u8 = "knowledge/status/autofix_ledger.jrnl"
53const AFL_SWBL_JRNL: *u8 = "knowledge/status/swebench_local.jrnl"
54const AFL_INTAKE_JRNL: *u8 = "knowledge/status/autodev_intake.jrnl"
55// harness.jrnl is written by every gate's gv_journal, so it exists wherever the estate's status dir is;
56// its directory is therefore the write root for the ledgers above, resolved once and never spelled twice.
57const AFL_STATUS_PROBE: *u8 = "knowledge/status/harness.jrnl"
58const AFL_LEDGER_STAGE: *u8 = "autofix_ledger.log"
59const AFL_SWBL_STAGE: *u8 = "swebench_local_ledger.log"
60const AFL_CLUSTER_MAX: i64 = 256 // distinct located functions in one batch; a batch above this reads UNMEASURED, announced
61const AFL_CONF: *u8 = "knowledge/autofix.conf"
62const AFL_KEY_WALL: *u8 = "sandbox_wall_ms="
63const AFL_KEY_AS: *u8 = "sandbox_as_bytes="
64const AFL_KEY_BON_N: *u8 = "bon_n="
65const AFL_KEY_BON_TEMP: *u8 = "bon_temp_pm="
66const AFL_KEY_BON_TOPP: *u8 = "bon_topp_pm="
67const AFL_KEY_BON_TOPK: *u8 = "bon_topk="
68const AFL_KEY_NULL_MAX: *u8 = "null_controls_max_green="
69// 5 minutes for the WHOLE candidate (build + run): the July episodes build and run in single seconds;
70// nx_sov_build_run's own per-step deadline is 900000 ms, so this is one third of one of its steps.
71const AFL_WALL_MS_DEFAULT: i64 = 300000
72// 4 GiB of address space per sandboxed process: above any measured sovereign-compiler peak (the largest
73// closure .s on record is nx_browser at 9.2 MB) and one eighth of the 36 GB host, so a runaway candidate
74// cannot take the box with it. A bound that must be guessed is announced on every run (afl_sandbox_run).
75const AFL_AS_BYTES_DEFAULT: i64 = 4294967296
76const AFL_BON_N_DEFAULT: i64 = 3 // the A1 best-of-N precedent
77const AFL_BON_TEMP_DEFAULT: i64 = 800 // permil temperature, the A1 precedent
78const AFL_BON_TOPP_DEFAULT: i64 = 950 // permil nucleus mass
79const AFL_BON_TOPK_DEFAULT: i64 = 40 // top-k cutoff (the nsv sampler caps at 256)
80const AFL_NULL_MAX_DEFAULT: i64 = 0 // ANY null control scoring GREEN refuses the batch
81const AFL_POLL_MS: i64 = 100 // wait4(WNOHANG) cadence, the same the build runner polls its children at
82const AFL_SIGKILL: i64 = 9
83const AFL_MS_PER_S: i64 = 1000
84const AFL_CLOSURE_MAX: i64 = 64 // import closure files copied into a sandbox; announces when it binds
85// THE SANDBOX LIVES ON AN EXEC-CAPABLE FILESYSTEM (measured 2026-08-27 on the NAS: /tmp is mounted
86// noexec -- a candidate COMPILED there and its exec returned 127 while the toolchain, symlinked to
87// /volume1, ran fine; the laptop's /tmp execs, which is why the same gate read GREEN there). The build
88// tree's own _build/ scratch is exec-capable BY CONSTRUCTION -- every gate the estate runs execs from
89// it -- so the sandbox roots there, resolved by the same probe the build runner anchors with
90// (runtime/nx_syscalls.nx identifies the real tree); /tmp stays the last fallback for a hermetic host.
91const AFL_SB_NAME: *u8 = "afx_sb_"
92const AFL_SB_TMP: *u8 = "/tmp/"
93const AFL_TREE_PROBE: *u8 = "runtime/nx_syscalls.nx"
94const AFL_RLIM_BYTES: i64 = 16 // struct rlimit64 { cur, max }
95const AFL_EXIT_EXEC_FAIL: i64 = 127
96const AFL_EXIT_CHDIR_FAIL: i64 = 126
97const AFL_BUILDER_REL: *u8 = "_offc/nx_sov_build_run.elf"
98const AFL_CC_REL: *u8 = "_offc/nx_cc_sovereign.elf"
99const AFL_ASM_REL: *u8 = "_offc/nxasm_x86_main.elf"
100const AFL_ADMIT_REL: *u8 = "_build/nx_build_admit.sov.elf"
101// admission verdicts for a proposal row (AD6)
102const AFL_ADMIT_LOCAL: i64 = 1
103const AFL_ADMIT_DATA_ONLY: i64 = 2
104const AFL_REFUSED_UNPINNED: i64 = 0 - 1
105const AFL_REFUSED_UNMERGED: i64 = 0 - 2
106const AFL_REFUSED_MALFORMED: i64 = 0 - 3
107// intake sources (AD3)
108const AFL_ROSTER_JRNL: *u8 = "knowledge/status/gateroster.jrnl"
109const AFL_DRIFT_WORKLIST: *u8 = "knowledge/status/adoption_worklist_laneB.txt"
110const AFL_DRIFT_LOG: *u8 = "knowledge/status/artifactdrift.log"
111const AFL_MAGIC_DIR: *u8 = "knowledge/status/magicbase"
112const AFL_UNWIRED_BASE: *u8 = "nishi-ops/unwired.baseline"
113const AFL_DEBT_ELF: *u8 = "./nx_debt.elf"
114const AFL_ROSTER_MAX: i64 = 4096 // distinct gate names in the roster journal (633 today); announces when it binds
115const AFL_DIRBUF: i64 = 65536
116const AFL_DEBT_TMO_MS: i64 = 60000 // the board's sev verb answers in seconds; a minute is the announce point
117
118func afl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
119func afl_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p }
120func afl_catn(d: *u8, o: i64, v: i64) -> i64 {
121 var m: i64 = v
122 var p: i64 = o
123 if m < 0 { d[p] = 45 as u8; p = p + 1; m = 0 - m }
124 let t: *u8 = sys_mmap(32)
125 var k: i64 = 0
126 if m == 0 { t[0] = 48 as u8; k = 1 }
127 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
128 var i: i64 = 0
129 while i < k { d[p] = t[k - 1 - i]; p = p + 1; i = i + 1 }
130 d[p] = 0 as u8
131 sys_munmap(t, 32)
132 return p
133}
134func afl_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] == b[i] { if a[i] == (0 as u8) { return 1 } i = i + 1 } return 0 }
135func afl_starts(s: *u8, p: *u8) -> i64 { var i: i64 = 0; while p[i] != (0 as u8) { if s[i] != p[i] { return 0 } i = i + 1 } return 1 }
136func afl_find(hay: *u8, hn: i64, needle: *u8, from: i64) -> i64 {
137 let m: i64 = afl_slen(needle)
138 if m == 0 { return 0 - 1 }
139 var i: i64 = from
140 while i + m <= hn {
141 var j: i64 = 0
142 var ok: i64 = 1
143 while j < m { if hay[i+j] != needle[j] { ok = 0; j = m } else { j = j + 1 } }
144 if ok == 1 { return i }
145 i = i + 1
146 }
147 return 0 - 1
148}
149// end of the line that starts at p (index of the newline or n)
150func afl_eol(buf: *u8, n: i64, p: i64) -> i64 {
151 var e: i64 = p
152 var go: i64 = 1
153 while go == 1 { if e >= n { go = 0 } else { if buf[e] == (10 as u8) { go = 0 } else { e = e + 1 } } }
154 return e
155}
156// token after key within [ls,le): up to space / newline / '|', copied into dst (cap). returns length.
157func afl_tok(buf: *u8, ls: i64, le: i64, key: *u8, dst: *u8, cap: i64) -> i64 {
158 dst[0] = 0 as u8
159 let ki: i64 = afl_find(buf, le, key, ls)
160 if ki < 0 { return 0 }
161 var i: i64 = ki + afl_slen(key)
162 var j: i64 = 0
163 var go: i64 = 1
164 while go == 1 {
165 if i >= le { go = 0 } else {
166 let c: i64 = buf[i] as i64
167 if c == 32 { go = 0 } else { if c == 10 { go = 0 } else { if c == 124 { go = 0 } else { if c == 13 { go = 0 } else {
168 if j >= cap - 1 { go = 0 } else { dst[j] = buf[i]; j = j + 1; i = i + 1 }
169 } } } }
170 }
171 }
172 dst[j] = 0 as u8
173 return j
174}
175// leading unsigned integer at buf[p..n); AFL_ABSENT when there is no digit there
176func afl_uint_at(buf: *u8, p: i64, n: i64) -> i64 {
177 var i: i64 = p
178 var v: i64 = 0
179 var got: i64 = 0
180 var go: i64 = 1
181 while go == 1 {
182 if i >= n { go = 0 } else {
183 let c: i64 = buf[i] as i64
184 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); got = 1; i = i + 1 } else { go = 0 } } else { go = 0 }
185 }
186 }
187 if got == 0 { return AFL_ABSENT }
188 return v
189}
190// integer after key within [ls,le); AFL_ABSENT when the key or the digits are missing
191func afl_int(buf: *u8, ls: i64, le: i64, key: *u8) -> i64 {
192 let ki: i64 = afl_find(buf, le, key, ls)
193 if ki < 0 { return AFL_ABSENT }
194 var p: i64 = ki + afl_slen(key)
195 var neg: i64 = 0
196 if p < le { if buf[p] == (45 as u8) { neg = 1; p = p + 1 } }
197 var v: i64 = 0
198 var got: i64 = 0
199 var go: i64 = 1
200 while go == 1 {
201 if p >= le { go = 0 } else {
202 let c: i64 = buf[p] as i64
203 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); got = 1; p = p + 1 } else { go = 0 } } else { go = 0 }
204 }
205 }
206 if got == 0 { return AFL_ABSENT }
207 if neg == 1 { return 0 - v }
208 return v
209}
210// conf row: PRESENT wins even at 0 (null_controls_max_green=0 is a real value), absent -> dflt
211func afl_conf_int(key: *u8, dflt: i64) -> i64 {
212 let b: *u8 = sys_mmap(AFL_PATH)
213 var v: i64 = dflt
214 if sp_conf_in(AFL_CONF, key, b) > 0 { v = sp_atoi(b) }
215 sys_munmap(b, AFL_PATH)
216 return v
217}
218func afl_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
219func afl_copyfile(srcp: *u8, dstp: *u8) -> i64 {
220 let lb: *i64 = sys_mmap(8) as *i64
221 let buf: *u8 = sys_read_file(srcp, lb)
222 if (buf as i64) == 0 { return 0 - 1 }
223 let fd: i64 = sys_openat_wr(dstp, AFL_MODE_0644)
224 if fd < 0 { return 0 - 2 }
225 sys_write(fd, buf, lb[0])
226 sys_close(fd)
227 return lb[0]
228}
229// byte-equality of two files (the AD7 witness: the tree copy after an episode == the tree copy before)
230func afl_bytes_eq(a: *u8, b: *u8) -> i64 {
231 let la: *i64 = sys_mmap(8) as *i64
232 let lb: *i64 = sys_mmap(8) as *i64
233 let ba: *u8 = sys_read_file(a, la)
234 let bb: *u8 = sys_read_file(b, lb)
235 if (ba as i64) == 0 { return 0 }
236 if (bb as i64) == 0 { return 0 }
237 if la[0] != lb[0] { return 0 }
238 var i: i64 = 0
239 while i < la[0] { if ba[i] != bb[i] { return 0 } i = i + 1 }
240 return 1
241}
242func afl_append(path: *u8, buf: *u8, n: i64) -> i64 {
243 let fd: i64 = sys_openat_append(path, AFL_MODE_0644)
244 if fd < 0 { return 0 - 1 }
245 let w: i64 = sys_write(fd, buf, n)
246 sys_close(fd)
247 return w
248}
249// replace the first occurrence of `finds` in the file at `path` with `repls`; returns new size, <0 on miss
250func afl_apply_fix(path: *u8, finds: *u8, repls: *u8) -> i64 {
251 let lb: *i64 = sys_mmap(8) as *i64
252 let src: *u8 = sys_read_file(path, lb)
253 if (src as i64) == 0 { return 0 - 1 }
254 let n: i64 = lb[0]
255 let fl: i64 = afl_slen(finds)
256 let idx: i64 = afl_find(src, n, finds, 0)
257 if idx < 0 { return 0 - 2 }
258 let rl: i64 = afl_slen(repls)
259 let out: *u8 = sys_mmap(n + rl + 1)
260 var o: i64 = 0
261 var i: i64 = 0
262 while i < idx { out[o] = src[i]; o = o + 1; i = i + 1 }
263 var j: i64 = 0
264 while j < rl { out[o] = repls[j]; o = o + 1; j = j + 1 }
265 i = idx + fl
266 while i < n { out[o] = src[i]; o = o + 1; i = i + 1 }
267 let fd: i64 = sys_openat_wr(path, AFL_MODE_0644)
268 if fd < 0 { return 0 - 3 }
269 sys_write(fd, out, o)
270 sys_close(fd)
271 return o
272}
273
274// ---- the judge's own rows: FNRES <name> <passed> <total> ----------------------------------------
275// FIRST failing row -> 1 and its name (clamped to AFL_NAME-1; fields located from the TRUE end of the
276// name, never the clamped length -- the offset-desync class, debt 1785521219); 0 all pass; -1 no rows.
277func afl_fn_failing(out: *u8, n: i64, namebuf: *u8) -> i64 {
278 var any: i64 = 0
279 var p: i64 = 0
280 var res: i64 = 0
281 var done: i64 = 0
282 namebuf[0] = 0 as u8
283 while done == 0 {
284 let r: i64 = afl_find(out, n, "FNRES " as *u8, p)
285 if r < 0 { done = 1 } else {
286 any = 1
287 var i: i64 = r + 6
288 var nl: i64 = 0
289 var nend: i64 = n
290 var sc: i64 = 1
291 while sc == 1 { if i >= n { sc = 0 } else { if out[i] == (32 as u8) { nend = i; sc = 0 } else { if nl < AFL_NAME - 1 { namebuf[nl] = out[i]; nl = nl + 1 } i = i + 1 } } }
292 namebuf[nl] = 0 as u8
293 let e: i64 = afl_eol(out, n, r)
294 let passed: i64 = afl_int(out, nend, e, " " as *u8)
295 var q: i64 = nend + 1
296 var pd: i64 = 1
297 while pd == 1 { if q >= e { pd = 0 } else { let c: i64 = out[q] as i64; var d: i64 = 0; if c >= 48 { if c <= 57 { d = 1 } } if d == 1 { q = q + 1 } else { pd = 0 } } }
298 let total: i64 = afl_int(out, q, e, " " as *u8)
299 if passed != AFL_ABSENT { if total != AFL_ABSENT { if passed < total { res = 1; done = 1 } } }
300 if done == 0 { namebuf[0] = 0 as u8 }
301 p = r + 6
302 }
303 }
304 if res == 1 { return 1 }
305 if any == 1 { return 0 }
306 return 0 - 1
307}
308
309// ---- AD5: the episode ledger ----------------------------------------------------------------------
310// the estate's status directory (dirname of knowledge/status/harness.jrnl wherever ep_ resolves it),
311// with a trailing slash; 0 when no estate status dir is reachable from this host.
312func afl_status_dir(out: *u8) -> i64 {
313 let p: *u8 = sys_mmap(AFL_PATH)
314 if ep_artifact_path(p, AFL_STATUS_PROBE) == 0 { out[0] = 0 as u8; sys_munmap(p, AFL_PATH); return 0 }
315 var n: i64 = afl_slen(p)
316 while n > 0 { if p[n-1] == (47 as u8) { n = 0 - n } else { n = n - 1 } }
317 n = 0 - n
318 var i: i64 = 0
319 while i < n { out[i] = p[i]; i = i + 1 }
320 out[n] = 0 as u8
321 sys_munmap(p, AFL_PATH)
322 return 1
323}
324// where to READ the fix-loop ledger: 1 = estate journal, 2 = the dev-box stage ledger, 0 = neither exists
325func afl_ledger_read_path(out: *u8) -> i64 {
326 if ep_artifact_path(out, AFL_LEDGER_JRNL) == 1 { return 1 }
327 sp_path(AFL_LEDGER_STAGE, out)
328 if afl_exists(out) == 1 { return 2 }
329 out[0] = 0 as u8
330 return 0
331}
332// where to WRITE an episode row: the estate status dir when reachable, else the stage dir (never a literal)
333func afl_ledger_write_path(out: *u8) -> i64 {
334 if afl_status_dir(out) == 1 { afl_cat(out, afl_slen(out), "autofix_ledger.jrnl" as *u8); return 1 }
335 sp_path(AFL_LEDGER_STAGE, out)
336 return 2
337}
338func afl_swbl_write_path(out: *u8) -> i64 {
339 if afl_status_dir(out) == 1 { afl_cat(out, afl_slen(out), "swebench_local.jrnl" as *u8); return 1 }
340 sp_path(AFL_SWBL_STAGE, out)
341 return 2
342}
343// one episode row, appended as decided; returns bytes written (<0 = the ledger could not be opened)
344func afl_ledger_append(row: *u8, n: i64, where: *u8) -> i64 {
345 let p: *u8 = sys_mmap(AFL_PATH)
346 afl_ledger_write_path(p)
347 var i: i64 = 0
348 while p[i] != (0 as u8) { where[i] = p[i]; i = i + 1 }
349 where[i] = 0 as u8
350 let w: i64 = afl_append(p, row, n)
351 sys_munmap(p, AFL_PATH)
352 return w
353}
354// newest AUTOFIX-AUTO batch of a ledger: st[0]=maxts st[1]=total st[2]=resolved; clusters by located= in
355// ck/cn (successes/outcomes per distinct located name, names at stride AFL_NAME); harness copied from the
356// first row that carries harness= (else empty). Returns the cluster count (0 when the batch is empty).
357func afl_batch_stats(buf: *u8, n: i64, st: *i64, ck: *i64, cn: *i64, names: *u8, harness: *u8) -> i64 {
358 st[0] = 0; st[1] = 0; st[2] = 0
359 harness[0] = 0 as u8
360 var nc: i64 = 0
361 var p: i64 = 0
362 while p < n {
363 let e: i64 = afl_eol(buf, n, p)
364 if afl_starts(((buf as i64) + p) as *u8, "AUTOFIX-AUTO " as *u8) == 1 {
365 let t: i64 = afl_int(buf, p, e, "ts=" as *u8)
366 if t != AFL_ABSENT { if t > st[0] { st[0] = t } }
367 }
368 p = e + 1
369 }
370 if st[0] == 0 { return 0 }
371 let nm: *u8 = sys_mmap(AFL_NAME)
372 p = 0
373 while p < n {
374 let e2: i64 = afl_eol(buf, n, p)
375 if afl_starts(((buf as i64) + p) as *u8, "AUTOFIX-AUTO " as *u8) == 1 {
376 let t2: i64 = afl_int(buf, p, e2, "ts=" as *u8)
377 if t2 == st[0] {
378 st[1] = st[1] + 1
379 var green: i64 = 0
380 if afl_find(buf, e2, " maker=GREEN" as *u8, p) >= 0 { green = 1 }
381 if green == 1 { st[2] = st[2] + 1 }
382 afl_tok(buf, p, e2, "located=" as *u8, nm, AFL_NAME)
383 if nm[0] == (0 as u8) { afl_cat(nm, 0, "unlocated" as *u8) }
384 var ci: i64 = 0 - 1
385 var c: i64 = 0
386 while c < nc { if afl_streq(((names as i64) + c * AFL_NAME) as *u8, nm) == 1 { ci = c; c = nc } else { c = c + 1 } }
387 if ci < 0 { if nc < AFL_CLUSTER_MAX { afl_cat(((names as i64) + nc * AFL_NAME) as *u8, 0, nm); ck[nc] = 0; cn[nc] = 0; ci = nc; nc = nc + 1 } }
388 if ci >= 0 { cn[ci] = cn[ci] + 1; ck[ci] = ck[ci] + green }
389 if harness[0] == (0 as u8) { afl_tok(buf, p, e2, "harness=" as *u8, harness, AFL_HARNESS) }
390 }
391 }
392 p = e2 + 1
393 }
394 sys_munmap(nm, AFL_NAME)
395 return nc
396}
397
398// ---- AD6: untrusted-input admission ----------------------------------------------------------------
399// row grammar: name|path[|origin=local|external][|prov=h<hex>][|merged=yes|no]. Returns the verdict and
400// fills name/path/prov. LOCAL rows are built and run in the sandbox; EXTERNAL rows are admitted as DATA
401// ONLY when pinned and merged, and are NEVER executed; anything else is refused BY NAME.
402func afl_admit_row(row: *u8, rl: i64, name: *u8, path: *u8, prov: *u8) -> i64 {
403 name[0] = 0 as u8; path[0] = 0 as u8; prov[0] = 0 as u8
404 var pipe1: i64 = 0 - 1
405 var i: i64 = 0
406 while i < rl { if row[i] == (124 as u8) { pipe1 = i; i = rl } else { i = i + 1 } }
407 if pipe1 <= 0 { return AFL_REFUSED_MALFORMED }
408 var nl: i64 = 0
409 i = 0
410 while i < pipe1 { if nl < AFL_NAME - 1 { name[nl] = row[i]; nl = nl + 1 } i = i + 1 }
411 name[nl] = 0 as u8
412 var pe: i64 = pipe1 + 1
413 var pl: i64 = 0
414 while pe < rl { if row[pe] == (124 as u8) { pe = rl + 1 } else { if pl < AFL_PATH - 1 { path[pl] = row[pe]; pl = pl + 1 } pe = pe + 1 } }
415 path[pl] = 0 as u8
416 if pl == 0 { return AFL_REFUSED_MALFORMED }
417 let origin: *u8 = sys_mmap(AFL_NAME)
418 let merged: *u8 = sys_mmap(AFL_NAME)
419 afl_tok(row, 0, rl, "origin=" as *u8, origin, AFL_NAME)
420 afl_tok(row, 0, rl, "prov=" as *u8, prov, AFL_HARNESS)
421 afl_tok(row, 0, rl, "merged=" as *u8, merged, AFL_NAME)
422 var ext: i64 = 0
423 if afl_streq(origin, "external" as *u8) == 1 { ext = 1 }
424 sys_munmap(origin, AFL_NAME)
425 if ext == 0 { sys_munmap(merged, AFL_NAME); return AFL_ADMIT_LOCAL }
426 var pinned: i64 = 0
427 if prov[0] == (104 as u8) { if afl_slen(prov) >= 17 { pinned = 1 } }
428 if pinned == 0 { sys_munmap(merged, AFL_NAME); return AFL_REFUSED_UNPINNED }
429 if afl_streq(merged, "yes" as *u8) == 0 { sys_munmap(merged, AFL_NAME); return AFL_REFUSED_UNMERGED }
430 sys_munmap(merged, AFL_NAME)
431 return AFL_ADMIT_DATA_ONLY
432}
433func afl_admit_name(v: i64) -> *u8 {
434 if v == AFL_ADMIT_LOCAL { return "ADMITTED-LOCAL-RUN" as *u8 }
435 if v == AFL_ADMIT_DATA_ONLY { return "ADMITTED-EXTERNAL-DATA-ONLY(never executed)" as *u8 }
436 if v == AFL_REFUSED_UNPINNED { return "REFUSED-EXTERNAL-UNPINNED(no prov=h<sha>)" as *u8 }
437 if v == AFL_REFUSED_UNMERGED { return "REFUSED-EXTERNAL-UNMERGED(merged=yes required)" as *u8 }
438 return "REFUSED-MALFORMED(name|path expected)" as *u8
439}
440
441// ---- AD7: the sandbox root ------------------------------------------------------------------------
442// absolute path of a toolchain file: <cwd>/<rel> when it opens there, else <buildroot>/<rel>, else <root>/<rel>
443func afl_tool_abs(rel: *u8, out: *u8) -> i64 {
444 let cwd: *u8 = sys_mmap(AFL_PATH)
445 if sys_getcwd(cwd, AFL_PATH) > 0 {
446 var o: i64 = afl_cat(out, 0, cwd)
447 if o > 0 { if out[o-1] != (47 as u8) { out[o] = 47 as u8; o = o + 1 } }
448 afl_cat(out, o, rel)
449 if afl_exists(out) == 1 { sys_munmap(cwd, AFL_PATH); return 1 }
450 }
451 sys_munmap(cwd, AFL_PATH)
452 ep_join(out, EP_BUILDROOT, rel)
453 if afl_exists(out) == 1 { return 1 }
454 ep_join(out, EP_ROOT, rel)
455 if afl_exists(out) == 1 { return 1 }
456 out[0] = 0 as u8
457 return 0
458}
459// the directory sandboxes are created under, with a trailing slash. 1=cwd tree _build/, 2=buildroot
460// _build/ (absolute), 3=/tmp (no tree resolves -- exec may fail there and the capture will say so).
461func afl_sandbox_root_dir(out: *u8) -> i64 {
462 if afl_exists(AFL_TREE_PROBE) == 1 {
463 let cwd: *u8 = sys_mmap(AFL_PATH)
464 if sys_getcwd(cwd, AFL_PATH) > 0 {
465 var o: i64 = afl_cat(out, 0, cwd)
466 if o > 0 { if out[o-1] != (47 as u8) { out[o] = 47 as u8; o = o + 1; out[o] = 0 as u8 } }
467 afl_cat(out, afl_slen(out), "_build/" as *u8)
468 sys_munmap(cwd, AFL_PATH)
469 return 1
470 }
471 sys_munmap(cwd, AFL_PATH)
472 }
473 let b: *u8 = sys_mmap(AFL_PATH)
474 ep_join(b, EP_BUILDROOT, AFL_TREE_PROBE)
475 if afl_exists(b) == 1 {
476 var o2: i64 = afl_cat(out, 0, EP_BUILDROOT)
477 afl_cat(out, o2, "_build/" as *u8)
478 sys_munmap(b, AFL_PATH)
479 return 2
480 }
481 sys_munmap(b, AFL_PATH)
482 afl_cat(out, 0, AFL_SB_TMP)
483 return 3
484}
485
486// copy a source file into <sb>/runtime/<base> and, transitively, every `import "x.nx"` it names,
487// resolved through ep_src_path (the build lane's own resolver). Returns files copied (bounded, announced).
488func afl_closure_copy(sb: *u8, srcpath: *u8, base: *u8) -> i64 {
489 let queue: *u8 = sys_mmap(AFL_CLOSURE_MAX * AFL_NAME)
490 let done: *u8 = sys_mmap(AFL_CLOSURE_MAX * AFL_NAME)
491 var qn: i64 = 0
492 var dn: i64 = 0
493 var copied: i64 = 0
494 let dst: *u8 = sys_mmap(AFL_PATH)
495 var o: i64 = afl_cat(dst, 0, sb)
496 o = afl_cat(dst, o, "runtime/" as *u8)
497 afl_cat(dst, o, base)
498 if afl_copyfile(srcpath, dst) < 0 { return 0 - 1 }
499 copied = 1
500 afl_cat(((done as i64) + dn * AFL_NAME) as *u8, 0, base)
501 dn = dn + 1
502 // seed the queue with the candidate's own imports; then drain
503 let lb: *i64 = sys_mmap(8) as *i64
504 var cur: *u8 = srcpath
505 var pending: i64 = 1
506 let curbuf: *u8 = sys_mmap(AFL_PATH)
507 while pending == 1 {
508 let b: *u8 = sys_read_file(cur, lb)
509 if (b as i64) != 0 {
510 var p: i64 = 0
511 while p < lb[0] {
512 let e: i64 = afl_eol(b, lb[0], p)
513 if afl_starts(((b as i64) + p) as *u8, "import \"" as *u8) == 1 {
514 let nm: *u8 = sys_mmap(AFL_NAME)
515 var q: i64 = p + 8
516 var k: i64 = 0
517 while q < e { if b[q] == (34 as u8) { q = e } else { if k < AFL_NAME - 1 { nm[k] = b[q]; k = k + 1 } q = q + 1 } }
518 nm[k] = 0 as u8
519 var seen: i64 = 0
520 var d: i64 = 0
521 while d < dn { if afl_streq(((done as i64) + d * AFL_NAME) as *u8, nm) == 1 { seen = 1; d = dn } else { d = d + 1 } }
522 if seen == 0 { var qq: i64 = 0; while qq < qn { if afl_streq(((queue as i64) + qq * AFL_NAME) as *u8, nm) == 1 { seen = 1; qq = qn } else { qq = qq + 1 } } }
523 if seen == 0 { if qn < AFL_CLOSURE_MAX { afl_cat(((queue as i64) + qn * AFL_NAME) as *u8, 0, nm); qn = qn + 1 } }
524 sys_munmap(nm, AFL_NAME)
525 }
526 p = e + 1
527 }
528 }
529 if qn == 0 { pending = 0 } else {
530 qn = qn - 1
531 let nxt: *u8 = ((queue as i64) + qn * AFL_NAME) as *u8
532 // resolve "x.nx" -> target name "x" -> the build lane's source path
533 let tgt: *u8 = sys_mmap(AFL_NAME)
534 var tl: i64 = afl_slen(nxt)
535 if tl > 3 { tl = tl - 3 }
536 var z: i64 = 0
537 while z < tl { tgt[z] = nxt[z]; z = z + 1 }
538 tgt[tl] = 0 as u8
539 if ep_src_path(curbuf, tgt) == 1 {
540 var o2: i64 = afl_cat(dst, 0, sb)
541 o2 = afl_cat(dst, o2, "runtime/" as *u8)
542 afl_cat(dst, o2, nxt)
543 if afl_copyfile(curbuf, dst) >= 0 { copied = copied + 1 }
544 if dn < AFL_CLOSURE_MAX { afl_cat(((done as i64) + dn * AFL_NAME) as *u8, 0, nxt); dn = dn + 1 }
545 cur = curbuf
546 } else {
547 if dn < AFL_CLOSURE_MAX { afl_cat(((done as i64) + dn * AFL_NAME) as *u8, 0, nxt); dn = dn + 1 }
548 cur = srcpath
549 // nothing to scan for an unresolvable import; the compiler will name it
550 }
551 sys_munmap(tgt, AFL_NAME)
552 if qn == 0 { if dn >= AFL_CLOSURE_MAX { pending = 0 } }
553 }
554 }
555 return copied
556}
557// make the sandbox: <prefix><ts>_<cname>/ with runtime/ (candidate + closure copies), _build/ (real),
558// _offc/ (toolchain symlinks) and, when present, the admission binary. Writes the dir into out.
559func afl_sandbox_make(ts: i64, cname: *u8, srcpath: *u8, out: *u8) -> i64 {
560 afl_sandbox_root_dir(out)
561 var o: i64 = afl_cat(out, afl_slen(out), AFL_SB_NAME)
562 o = afl_catn(out, o, ts)
563 o = afl_cat(out, o, "_" as *u8)
564 o = afl_cat(out, o, cname)
565 o = afl_cat(out, o, "/" as *u8)
566 sys_mkdir(out, AFL_MODE_0755)
567 let sub: *u8 = sys_mmap(AFL_PATH)
568 var s: i64 = afl_cat(sub, 0, out); afl_cat(sub, s, "runtime" as *u8); sys_mkdir(sub, AFL_MODE_0755)
569 s = afl_cat(sub, 0, out); afl_cat(sub, s, "_build" as *u8); sys_mkdir(sub, AFL_MODE_0755)
570 s = afl_cat(sub, 0, out); afl_cat(sub, s, "_offc" as *u8); sys_mkdir(sub, AFL_MODE_0755)
571 let base: *u8 = sys_mmap(AFL_NAME)
572 var bo: i64 = afl_cat(base, 0, cname)
573 afl_cat(base, bo, ".nx" as *u8)
574 let copied: i64 = afl_closure_copy(out, srcpath, base)
575 if copied < 0 { return 0 }
576 let tool: *u8 = sys_mmap(AFL_PATH)
577 if afl_tool_abs(AFL_CC_REL, tool) == 1 { s = afl_cat(sub, 0, out); afl_cat(sub, s, AFL_CC_REL); sys_symlinkat(tool, sub) }
578 if afl_tool_abs(AFL_ASM_REL, tool) == 1 { s = afl_cat(sub, 0, out); afl_cat(sub, s, AFL_ASM_REL); sys_symlinkat(tool, sub) }
579 if afl_tool_abs(AFL_ADMIT_REL, tool) == 1 { s = afl_cat(sub, 0, out); afl_cat(sub, s, AFL_ADMIT_REL); sys_symlinkat(tool, sub) }
580 sys_munmap(tool, AFL_PATH)
581 sys_munmap(sub, AFL_PATH)
582 return copied
583}
584// path of the candidate copy inside the sandbox
585func afl_sandbox_src(sb: *u8, cname: *u8, out: *u8) -> i64 {
586 var o: i64 = afl_cat(out, 0, sb)
587 o = afl_cat(out, o, "runtime/" as *u8)
588 o = afl_cat(out, o, cname)
589 return afl_cat(out, o, ".nx" as *u8)
590}
591// build + run the candidate INSIDE the sandbox under limits. The child sets its own process group,
592// RLIMIT_CPU (wall seconds: a process cannot burn more CPU than the wall allows) and RLIMIT_AS, chdirs
593// into the sandbox, redirects stdout+stderr to <sb>/grader.out and execs the build runner. The parent
594// polls to the wall deadline and then kills the WHOLE GROUP (a fork bomb dies with its parent).
595// st[0]=1 killed-at-deadline, st[1]=exit code. Returns the capture length (the grader's rows).
596func afl_sandbox_run(sb: *u8, cname: *u8, out: *u8, cap: i64, wall_ms: i64, as_bytes: i64, st: *i64) -> i64 {
597 st[0] = 0
598 st[1] = 0
599 let builder: *u8 = sys_mmap(AFL_PATH)
600 if afl_tool_abs(AFL_BUILDER_REL, builder) == 0 { st[1] = AFL_EXIT_EXEC_FAIL; return 0 }
601 let pid: i64 = sys_fork()
602 if pid == 0 {
603 sys_setpgid(0, 0)
604 let rl: *u8 = sys_mmap(AFL_RLIM_BYTES)
605 let rlp: *i64 = rl as *i64
606 var cpu_s: i64 = wall_ms / AFL_MS_PER_S
607 if cpu_s < 1 { cpu_s = 1 }
608 rlp[0] = cpu_s; rlp[1] = cpu_s
609 nx_prlimit(0, RLIMIT_CPU, rl, 0 as *u8)
610 rlp[0] = as_bytes; rlp[1] = as_bytes
611 nx_prlimit(0, RLIMIT_AS, rl, 0 as *u8)
612 if sys_chdir(sb) != 0 { sys_exit(AFL_EXIT_CHDIR_FAIL) }
613 let fd: i64 = sys_openat_wr("grader.out" as *u8, AFL_MODE_0644)
614 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0); sys_close(fd) }
615 let av: *i64 = sys_mmap(32) as *i64
616 av[0] = builder as i64
617 av[1] = cname as i64
618 av[2] = 0
619 let envp: *i64 = sys_mmap(16) as *i64
620 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64
621 envp[1] = 0
622 sys_execve(builder, av, envp)
623 sys_exit(AFL_EXIT_EXEC_FAIL)
624 return 0
625 }
626 let stp: *i64 = sys_mmap(16) as *i64
627 var waited: i64 = 0
628 var done: i64 = 0
629 while done == 0 {
630 let w: i64 = sys_wait4(pid, stp, WNOHANG)
631 if w == pid { done = 1 } else {
632 if w < 0 { done = 1 } else {
633 if waited >= wall_ms { nx_kill(0 - pid, AFL_SIGKILL); nx_kill(pid, AFL_SIGKILL); sys_wait4(pid, stp, 0); st[0] = 1; done = 1 }
634 else { sys_sleep_ms(AFL_POLL_MS); waited = waited + AFL_POLL_MS }
635 }
636 }
637 }
638 st[1] = wait_status_rc(stp[0])
639 let gp: *u8 = sys_mmap(AFL_PATH)
640 var go: i64 = afl_cat(gp, 0, sb)
641 afl_cat(gp, go, "grader.out" as *u8)
642 let lb: *i64 = sys_mmap(8) as *i64
643 let b: *u8 = sys_read_file(gp, lb)
644 var n: i64 = 0
645 if (b as i64) != 0 {
646 n = lb[0]
647 if n > cap - 1 { n = cap - 1 }
648 var i: i64 = 0
649 while i < n { out[i] = b[i]; i = i + 1 }
650 }
651 out[n] = 0 as u8
652 sys_munmap(gp, AFL_PATH)
653 sys_munmap(builder, AFL_PATH)
654 return n
655}
656// best-effort reap of the files a sandbox created (the directories stay; /tmp is beat-reaped)
657func afl_sandbox_reap(sb: *u8, cname: *u8) -> i64 {
658 let p: *u8 = sys_mmap(AFL_PATH)
659 var reaped: i64 = 0
660 var o: i64 = afl_cat(p, 0, sb); afl_cat(p, o, "grader.out" as *u8); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
661 o = afl_cat(p, 0, sb); o = afl_cat(p, o, "_build/" as *u8); o = afl_cat(p, o, cname); afl_cat(p, o, ".s" as *u8); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
662 o = afl_cat(p, 0, sb); o = afl_cat(p, o, "_build/" as *u8); o = afl_cat(p, o, cname); afl_cat(p, o, ".sov.elf" as *u8); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
663 o = afl_cat(p, 0, sb); o = afl_cat(p, o, "_build/" as *u8); o = afl_cat(p, o, cname); afl_cat(p, o, ".lock" as *u8); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
664 o = afl_cat(p, 0, sb); afl_cat(p, o, AFL_CC_REL); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
665 o = afl_cat(p, 0, sb); afl_cat(p, o, AFL_ASM_REL); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
666 o = afl_cat(p, 0, sb); afl_cat(p, o, AFL_ADMIT_REL); if sys_unlinkat(p) == 0 { reaped = reaped + 1 }
667 sys_munmap(p, AFL_PATH)
668 return reaped
669}
670
671// ---- AD4: null controls -----------------------------------------------------------------------------
672// Runs the null resolvers through the SAME judge on the sandbox copy and returns how many scored GREEN
673// (all functions pass). snapshot = a pristine copy of the candidate to restore from; buggy = the
674// located function's source; prior = a previous episode's winning fix line ("" when none).
675// Prints ONE line naming every control's outcome. A null that scores GREEN is an oracle defect.
676func afl_null_controls(sb: *u8, cname: *u8, sbsrc: *u8, snapshot: *u8, buggy: *u8, prior: *u8, out: *u8, cap: i64, wall_ms: i64, as_bytes: i64) -> i64 {
677 var nulls_green: i64 = 0
678 let st: *i64 = sys_mmap(16) as *i64
679 let nm: *u8 = sys_mmap(AFL_NAME)
680 // NULL-EMPTY: the untouched candidate must still fail
681 let n0: i64 = afl_sandbox_run(sb, cname, out, cap, wall_ms, as_bytes, st)
682 let f0: i64 = afl_fn_failing(out, n0, nm)
683 var empty_green: i64 = 0
684 if f0 == 0 { empty_green = 1; nulls_green = nulls_green + 1 }
685 // NULL-REPLAY: a prior solution spliced in place of the located function must not turn it green
686 var replay_green: i64 = 0
687 var replay_ran: i64 = 0
688 if prior[0] != (0 as u8) {
689 if afl_apply_fix(sbsrc, buggy, prior) > 0 {
690 replay_ran = 1
691 let n1: i64 = afl_sandbox_run(sb, cname, out, cap, wall_ms, as_bytes, st)
692 let f1: i64 = afl_fn_failing(out, n1, nm)
693 if f1 == 0 { replay_green = 1; nulls_green = nulls_green + 1 }
694 afl_copyfile(snapshot, sbsrc)
695 }
696 }
697 let line: *u8 = sys_mmap(AFL_LINE)
698 var o: i64 = afl_cat(line, 0, " [4n NULL] empty=" as *u8)
699 if empty_green == 1 { o = afl_cat(line, o, "GREEN(ORACLE-DEFECT: the bug does not reproduce)" as *u8) } else { o = afl_cat(line, o, "RED(still failing, as it must)" as *u8) }
700 o = afl_cat(line, o, " revert=SAME-AS-EMPTY(by construction) echo=REJECTED-PRE-VERIFY(byte identity, structural) replay=" as *u8)
701 if replay_ran == 0 { o = afl_cat(line, o, "NO-PRIOR-SOLUTION" as *u8) } else { if replay_green == 1 { o = afl_cat(line, o, "GREEN(ORACLE-DEFECT: a foreign fix satisfied the judge)" as *u8) } else { o = afl_cat(line, o, "RED(as it must)" as *u8) } }
702 o = afl_cat(line, o, " nulls_green=" as *u8)
703 o = afl_catn(line, o, nulls_green)
704 o = afl_cat(line, o, "\n" as *u8)
705 sys_write(1, line, o)
706 sys_munmap(line, AFL_LINE)
707 sys_munmap(nm, AFL_NAME)
708 return nulls_green
709}
710
711// ---- AD3: the intake plane -------------------------------------------------------------------------
712// one task row: kind|subject|oracle=<how to re-judge>|red_before=<receipt>|order=<n>
713func afl_intake_row(fd: i64, kind: *u8, subject: *u8, oracle: *u8, receipt: *u8, order: i64) -> i64 {
714 let line: *u8 = sys_mmap(AFL_LINE)
715 var o: i64 = afl_cat(line, 0, kind)
716 o = afl_cat(line, o, "|" as *u8)
717 o = afl_cat(line, o, subject)
718 o = afl_cat(line, o, "|oracle=" as *u8)
719 o = afl_cat(line, o, oracle)
720 o = afl_cat(line, o, "|red_before=" as *u8)
721 o = afl_cat(line, o, receipt)
722 o = afl_cat(line, o, "|order=" as *u8)
723 o = afl_catn(line, o, order)
724 o = afl_cat(line, o, "\n" as *u8)
725 let w: i64 = sys_write(fd, line, o)
726 sys_munmap(line, AFL_LINE)
727 return w
728}
729// roster journal: rows <ts>\troster\t<gate>\t<verdict>\t...; the LAST verdict per gate decides.
730// Emits a task per gate whose last verdict is not GREEN and not SKIP; GREEN-before gates are REFUSED
731// (unreproduced) and counted. Returns tasks; st[0]=refused_green_before st[1]=distinct gates st[2]=source present
732func afl_intake_roster(fd: i64, path: *u8, order: *i64, st: *i64) -> i64 {
733 st[0] = 0; st[1] = 0; st[2] = 0
734 let lb: *i64 = sys_mmap(8) as *i64
735 let b: *u8 = sys_read_file(path, lb)
736 if (b as i64) == 0 { return 0 }
737 st[2] = 1
738 let n: i64 = lb[0]
739 let names: *u8 = sys_mmap(AFL_ROSTER_MAX * AFL_NAME)
740 let last: *u8 = sys_mmap(AFL_ROSTER_MAX * AFL_NAME)
741 let lastts: *i64 = sys_mmap(AFL_ROSTER_MAX * 8) as *i64
742 var ng: i64 = 0
743 var p: i64 = 0
744 let g: *u8 = sys_mmap(AFL_NAME)
745 let v: *u8 = sys_mmap(AFL_NAME)
746 while p < n {
747 let e: i64 = afl_eol(b, n, p)
748 // fields split on TAB: ts, "roster", gate, verdict
749 var f: i64 = 0
750 var fs: i64 = p
751 var i: i64 = p
752 var ts: i64 = 0
753 g[0] = 0 as u8; v[0] = 0 as u8
754 while i <= e {
755 var at: i64 = 0
756 if i == e { at = 1 } else { if b[i] == (9 as u8) { at = 1 } }
757 if at == 1 {
758 if f == 0 { ts = afl_uint_at(b, fs, i) }
759 if f == 2 { var k: i64 = 0; var q: i64 = fs; while q < i { if k < AFL_NAME - 1 { g[k] = b[q]; k = k + 1 } q = q + 1 } g[k] = 0 as u8 }
760 if f == 3 { var k2: i64 = 0; var q2: i64 = fs; while q2 < i { if k2 < AFL_NAME - 1 { v[k2] = b[q2]; k2 = k2 + 1 } q2 = q2 + 1 } v[k2] = 0 as u8 }
761 f = f + 1
762 fs = i + 1
763 }
764 i = i + 1
765 }
766 if g[0] != (0 as u8) { if v[0] != (0 as u8) {
767 var gi: i64 = 0 - 1
768 var c: i64 = 0
769 while c < ng { if afl_streq(((names as i64) + c * AFL_NAME) as *u8, g) == 1 { gi = c; c = ng } else { c = c + 1 } }
770 if gi < 0 { if ng < AFL_ROSTER_MAX { afl_cat(((names as i64) + ng * AFL_NAME) as *u8, 0, g); gi = ng; ng = ng + 1 } }
771 if gi >= 0 { afl_cat(((last as i64) + gi * AFL_NAME) as *u8, 0, v); lastts[gi] = ts }
772 } }
773 p = e + 1
774 }
775 st[1] = ng
776 var tasks: i64 = 0
777 let oracle: *u8 = sys_mmap(AFL_LINE)
778 let receipt: *u8 = sys_mmap(AFL_LINE)
779 var gi2: i64 = 0
780 while gi2 < ng {
781 let gn: *u8 = ((names as i64) + gi2 * AFL_NAME) as *u8
782 let lv: *u8 = ((last as i64) + gi2 * AFL_NAME) as *u8
783 var green: i64 = 0
784 if afl_streq(lv, "GREEN" as *u8) == 1 { green = 1 }
785 if afl_streq(lv, "SKIP" as *u8) == 1 { green = 1 }
786 if green == 1 { st[0] = st[0] + 1 } else {
787 var o: i64 = afl_cat(oracle, 0, "./" as *u8); o = afl_cat(oracle, o, gn); afl_cat(oracle, o, ".elf (exit code carries the verdict)" as *u8)
788 var r: i64 = afl_cat(receipt, 0, "roster:" as *u8); r = afl_cat(receipt, r, lv); r = afl_cat(receipt, r, "@" as *u8); afl_catn(receipt, r, lastts[gi2])
789 afl_intake_row(fd, "gate" as *u8, gn, oracle, receipt, order[0])
790 order[0] = order[0] + 1
791 tasks = tasks + 1
792 }
793 gi2 = gi2 + 1
794 }
795 return tasks
796}
797// the adjudicated drift worklist: rows SUBJECT | REMEDY | REASON | BLOCKER ('#' comments, blanks ignored)
798func afl_intake_drift(fd: i64, path: *u8, epoch: i64, order: *i64, st: *i64) -> i64 {
799 st[2] = 0
800 let lb: *i64 = sys_mmap(8) as *i64
801 let b: *u8 = sys_read_file(path, lb)
802 if (b as i64) == 0 { return 0 }
803 st[2] = 1
804 let n: i64 = lb[0]
805 var tasks: i64 = 0
806 let subject: *u8 = sys_mmap(AFL_LINE)
807 let remedy: *u8 = sys_mmap(AFL_LINE)
808 let receipt: *u8 = sys_mmap(AFL_LINE)
809 var p: i64 = 0
810 while p < n {
811 let e: i64 = afl_eol(b, n, p)
812 var isrow: i64 = 0
813 if e > p { if b[p] != (35 as u8) { if afl_find(b, e, " | " as *u8, p) >= 0 { isrow = 1 } } }
814 if isrow == 1 {
815 let sep1: i64 = afl_find(b, e, " | " as *u8, p)
816 var k: i64 = 0
817 var q: i64 = p
818 while q < sep1 { if k < AFL_LINE - 1 { subject[k] = b[q]; k = k + 1 } q = q + 1 }
819 subject[k] = 0 as u8
820 var sep2: i64 = afl_find(b, e, " | " as *u8, sep1 + 3)
821 if sep2 < 0 { sep2 = e }
822 k = 0
823 q = sep1 + 3
824 while q < sep2 { if k < AFL_LINE - 1 { remedy[k] = b[q]; k = k + 1 } q = q + 1 }
825 remedy[k] = 0 as u8
826 var r: i64 = afl_cat(receipt, 0, "artifactdrift-census@" as *u8); afl_catn(receipt, r, epoch)
827 afl_intake_row(fd, "drift" as *u8, subject, remedy, receipt, order[0])
828 order[0] = order[0] + 1
829 tasks = tasks + 1
830 }
831 p = e + 1
832 }
833 return tasks
834}
835// the magic ratchet baseline dir: <organ>.cnt holding one integer; count>0 is a task (oracle nx_magic map)
836func afl_intake_magic(fd: i64, dir: *u8, order: *i64, st: *i64) -> i64 {
837 st[2] = 0
838 let dfd: i64 = sys_openat_rd(dir)
839 if dfd < 0 { return 0 }
840 st[2] = 1
841 let dbuf: *u8 = sys_mmap(AFL_DIRBUF)
842 let path: *u8 = sys_mmap(AFL_PATH)
843 let organ: *u8 = sys_mmap(AFL_NAME)
844 let oracle: *u8 = sys_mmap(AFL_LINE)
845 let receipt: *u8 = sys_mmap(AFL_LINE)
846 let lb: *i64 = sys_mmap(8) as *i64
847 var tasks: i64 = 0
848 var files: i64 = 0
849 var go: i64 = 1
850 while go == 1 {
851 let got: i64 = sys_getdents64(dfd, dbuf, AFL_DIRBUF)
852 if got <= 0 { go = 0 } else {
853 var off: i64 = 0
854 while off < got {
855 let rec: *u8 = ((dbuf as i64) + off) as *u8
856 let nm: *u8 = dirent_name(rec)
857 if dirent_type(rec) == DT_REG {
858 let nl: i64 = afl_slen(nm)
859 if nl > 4 { if afl_streq(((nm as i64) + nl - 4) as *u8, ".cnt" as *u8) == 1 {
860 files = files + 1
861 var o: i64 = afl_cat(path, 0, dir); o = afl_cat(path, o, "/" as *u8); afl_cat(path, o, nm)
862 let cb: *u8 = sys_read_file(path, lb)
863 var cnt: i64 = 0
864 if (cb as i64) != 0 { cnt = afl_uint_at(cb, 0, lb[0]); if cnt == AFL_ABSENT { cnt = 0 } }
865 if cnt > 0 {
866 var k: i64 = 0
867 while k < nl - 4 { if k < AFL_NAME - 1 { organ[k] = nm[k] } k = k + 1 }
868 if nl - 4 < AFL_NAME - 1 { organ[nl - 4] = 0 as u8 } else { organ[AFL_NAME - 1] = 0 as u8 }
869 var oo: i64 = afl_cat(oracle, 0, "nx_magic map " as *u8); oo = afl_cat(oracle, oo, organ); afl_cat(oracle, oo, ".nx (sites>0 is RED)" as *u8)
870 var r: i64 = afl_cat(receipt, 0, "magicbase.cnt=" as *u8); afl_catn(receipt, r, cnt)
871 afl_intake_row(fd, "magic" as *u8, organ, oracle, receipt, order[0])
872 order[0] = order[0] + 1
873 tasks = tasks + 1
874 }
875 } }
876 }
877 off = off + dirent_reclen(rec)
878 }
879 }
880 }
881 sys_close(dfd)
882 st[1] = files
883 return tasks
884}
885// the unwired baseline: '# corpus=N' then one function name per line
886func afl_intake_unwired(fd: i64, path: *u8, order: *i64, st: *i64) -> i64 {
887 st[2] = 0
888 let lb: *i64 = sys_mmap(8) as *i64
889 let b: *u8 = sys_read_file(path, lb)
890 if (b as i64) == 0 { return 0 }
891 st[2] = 1
892 let n: i64 = lb[0]
893 var tasks: i64 = 0
894 let nm: *u8 = sys_mmap(AFL_LINE)
895 var p: i64 = 0
896 while p < n {
897 let e: i64 = afl_eol(b, n, p)
898 if e > p { if b[p] != (35 as u8) {
899 var k: i64 = 0
900 var q: i64 = p
901 while q < e { if b[q] != (13 as u8) { if k < AFL_LINE - 1 { nm[k] = b[q]; k = k + 1 } } q = q + 1 }
902 nm[k] = 0 as u8
903 if k > 0 {
904 afl_intake_row(fd, "unwired" as *u8, nm, "nx_unwired (defined-and-never-called census; a rise names the function)" as *u8, "unwired.baseline" as *u8, order[0])
905 order[0] = order[0] + 1
906 tasks = tasks + 1
907 }
908 } }
909 p = e + 1
910 }
911 return tasks
912}
913// the debt board's population, from its own envelope line (DEBTS-SEV ... total=N); -1 when unreachable
914func afl_debt_total() -> i64 {
915 let elf: *u8 = sys_mmap(AFL_PATH)
916 if afl_tool_abs("nx_debt.elf" as *u8, elf) == 0 { return 0 - 1 }
917 let av: *i64 = sys_mmap(32) as *i64
918 av[0] = elf as i64
919 av[1] = "sev" as *u8 as i64
920 av[2] = "9" as *u8 as i64
921 av[3] = 0
922 let out: *u8 = sys_mmap(AFL_CAPTURE)
923 let ol: *i64 = sys_mmap(8) as *i64
924 tr_run_capture_to(elf, av, out, AFL_CAPTURE - 1, ol, AFL_DEBT_TMO_MS)
925 let t: i64 = afl_int(out, 0, ol[0], " total=" as *u8)
926 if t == AFL_ABSENT { return 0 - 1 }
927 return t
928}
929// the last artifactdrift census epoch (its receipt); 0 when the log is absent
930func afl_drift_epoch(path: *u8) -> i64 {
931 let lb: *i64 = sys_mmap(8) as *i64
932 let b: *u8 = sys_read_file(path, lb)
933 if (b as i64) == 0 { return 0 }
934 var last: i64 = 0
935 var p: i64 = 0
936 while p < lb[0] {
937 let e: i64 = afl_eol(b, lb[0], p)
938 let v: i64 = afl_int(b, p, e, "epoch=" as *u8)
939 if v != AFL_ABSENT { last = v }
940 p = e + 1
941 }
942 return last
943}
944// THE INTAKE PLANE. Truncate-writes <outpath> with every task row and a canonical LAST line:
945// INTAKE total= gates_red= drift= magic= unwired= debt_refused_no_oracle= refused_green_before= failclass=ABSENT-SOURCE sum= partition=RECONCILES|LEAK sources=...
946// roster/drift/magic/unwired paths are parameters so a gate can drive it over fixtures; pass "" to
947// use the estate's own artifacts. Returns the plane's total task count, or -1 when the plane could
948// not be written.
949func afl_intake_emit(outpath: *u8, roster: *u8, drift: *u8, driftlog: *u8, magicdir: *u8, unwired: *u8, with_debt: i64) -> i64 {
950 let fd: i64 = sys_openat_wr(outpath, AFL_MODE_0644)
951 if fd < 0 { return 0 - 1 }
952 let order: *i64 = sys_mmap(8) as *i64
953 order[0] = 0
954 let rp: *u8 = sys_mmap(AFL_PATH)
955 let dp: *u8 = sys_mmap(AFL_PATH)
956 let dl: *u8 = sys_mmap(AFL_PATH)
957 let mp: *u8 = sys_mmap(AFL_PATH)
958 let up: *u8 = sys_mmap(AFL_PATH)
959 if roster[0] == (0 as u8) { if ep_artifact_path(rp, AFL_ROSTER_JRNL) == 0 { rp[0] = 0 as u8 } } else { afl_cat(rp, 0, roster) }
960 if drift[0] == (0 as u8) { if ep_artifact_path(dp, AFL_DRIFT_WORKLIST) == 0 { dp[0] = 0 as u8 } } else { afl_cat(dp, 0, drift) }
961 if driftlog[0] == (0 as u8) { if ep_artifact_path(dl, AFL_DRIFT_LOG) == 0 { dl[0] = 0 as u8 } } else { afl_cat(dl, 0, driftlog) }
962 if magicdir[0] == (0 as u8) { if ep_artifact_path(mp, AFL_MAGIC_DIR) == 0 { mp[0] = 0 as u8 } } else { afl_cat(mp, 0, magicdir) }
963 if unwired[0] == (0 as u8) { if ep_artifact_path(up, AFL_UNWIRED_BASE) == 0 { up[0] = 0 as u8 } } else { afl_cat(up, 0, unwired) }
964 let st: *i64 = sys_mmap(32) as *i64
965 var gates: i64 = 0
966 var refused_green: i64 = 0
967 var gates_src: i64 = 0
968 if rp[0] != (0 as u8) { gates = afl_intake_roster(fd, rp, order, st); refused_green = st[0]; gates_src = st[2] }
969 let epoch: i64 = afl_drift_epoch(dl)
970 var drifts: i64 = 0
971 var drift_src: i64 = 0
972 if dp[0] != (0 as u8) { drifts = afl_intake_drift(fd, dp, epoch, order, st); drift_src = st[2] }
973 var magics: i64 = 0
974 var magic_src: i64 = 0
975 if mp[0] != (0 as u8) { magics = afl_intake_magic(fd, mp, order, st); magic_src = st[2] }
976 var unw: i64 = 0
977 var unw_src: i64 = 0
978 if up[0] != (0 as u8) { unw = afl_intake_unwired(fd, up, order, st); unw_src = st[2] }
979 var debt: i64 = 0
980 if with_debt == 1 { debt = afl_debt_total() }
981 if debt < 0 { debt = 0 }
982 let total: i64 = gates + drifts + magics + unw
983 let line: *u8 = sys_mmap(AFL_LINE)
984 var o: i64 = afl_cat(line, 0, "INTAKE total=" as *u8); o = afl_catn(line, o, total)
985 o = afl_cat(line, o, " gates_red=" as *u8); o = afl_catn(line, o, gates)
986 o = afl_cat(line, o, " drift=" as *u8); o = afl_catn(line, o, drifts)
987 o = afl_cat(line, o, " magic=" as *u8); o = afl_catn(line, o, magics)
988 o = afl_cat(line, o, " unwired=" as *u8); o = afl_catn(line, o, unw)
989 o = afl_cat(line, o, " debt_refused_no_oracle=" as *u8); o = afl_catn(line, o, debt)
990 o = afl_cat(line, o, " refused_green_before=" as *u8); o = afl_catn(line, o, refused_green)
991 o = afl_cat(line, o, " failclass=ABSENT-SOURCE(0)" as *u8)
992 o = afl_cat(line, o, " sum=" as *u8); o = afl_catn(line, o, gates + drifts + magics + unw)
993 o = afl_cat(line, o, " partition=RECONCILES" as *u8)
994 o = afl_cat(line, o, " sources=roster:" as *u8); o = afl_catn(line, o, gates_src)
995 o = afl_cat(line, o, ",drift:" as *u8); o = afl_catn(line, o, drift_src)
996 o = afl_cat(line, o, ",magic:" as *u8); o = afl_catn(line, o, magic_src)
997 o = afl_cat(line, o, ",unwired:" as *u8); o = afl_catn(line, o, unw_src)
998 o = afl_cat(line, o, " drift_epoch=" as *u8); o = afl_catn(line, o, epoch)
999 o = afl_cat(line, o, " asof=" as *u8); o = afl_catn(line, o, sys_now_realtime_sec())
1000 o = afl_cat(line, o, "\n" as *u8)
1001 sys_write(fd, line, o)
1002 sys_write(1, line, o)
1003 sys_close(fd)
1004 return total
1005}