nx_zeroprint.nx
buildroot/runtime/nx_zeroprint.nx
about
nx_zeroprint.nx -- THE ZERO-PRINTS-AS-NUL DETECTOR AND REPAIRER.
FOUND 2026-08-26 while adding a DNS diagnostic: a field printed "ancount= " with nothing after it.
The value was 0. The shape, repeated by hand across the estate, is a decimal printer that writes
its digits into one buffer and reverses them into another:
if m == 0 { b[0] = 48 as u8; k = 1 } <-- '0' written to b
let t: *u8 = sys_mmap(24)
while m > 0 { t[k] = ...; k = k + 1 } <-- digits written to t
while i < k { b[i] = t[k-1-i]; i = i+1 } <-- reversal reads t, OVERWRITING b[0]
With m == 0 the digit loop never runs, so t is untouched mmap memory (zero-filled) and the
reversal copies a NUL byte over the '0'. A zero therefore prints as an INVISIBLE BYTE. That is
the worst possible failure direction for a diagnostic: the field reads as ABSENT rather than as
the value zero, and "absent" and "zero" demand opposite conclusions from whoever is reading it.
WHY THIS IS AN ORGAN AND NOT A ONE-OFF SWEEP: the first census of this was written in Python --
shell-shaped work that counted, classified and judged, which is precisely the shape the estate
forbids, and it published a wrong number (28) because it could not see the safe else-form. The
count belongs in a NishiLang organ that can be re-run, gated, and pointed at either tree.
THE CLASSIFICATION IS A PARTITION AND IT IS PRINTED, because three of the four buckets look
identical to a careless matcher:
EARLY-RETURN if m == 0 { b[0] = 48; sys_write(...); return 0 } -- prints and leaves. SAFE.
ELSE-FORM if m == 0 { ... } else { ...digit loop + reversal... } -- reversal is inside the
else and cannot run when m == 0. SAFE. This is the bucket the Python missed, and
missing it inflated the defect count by six.
SAME-BUFFER the zero branch writes the buffer the digit loop writes. The reversal reads back
a real '0'. SAFE -- this is the majority and the shared printer in nx_syscalls.nx.
DEFECTIVE zero branch writes X, digit loop writes Y, X != Y. The NUL case above.
REPAIR is a pure statement reorder, not a rewrite: the declaration of Y already sits between the
zero branch and the digit loop, so moving the zero branch BELOW that declaration and retargeting
it at Y makes the reversal read a real '0'. Nothing else about the function changes.
NO SEARCH WINDOW CONSTANT. A "look ahead N bytes" bound would be a guess and would silently
under-report on a long function. The digit loop is searched for only up to the START OF THE NEXT
FUNCTION, which is exact and needs no number.
verbs: scan <root> census only, exit 1 if any DEFECTIVE remain (gate-friendly)
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 45 | const ZP_EXIT_CLEAN: i64 = 0 |
| 46 | const ZP_EXIT_FOUND: i64 = 1 |
| 47 | const ZP_EXIT_USAGE: i64 = 3 |
functions
| 49 | func zp_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 50 | func zp_putn(v: i64) -> i64 |
| 65 | func zp_is_ws(c: i64) -> i64 { if c == 32 { return 1 } if c == 9 { return 1 } if c == 10 { return 1 } if c == 13 { return 1 } return 0 } |
| 66 | func zp_is_id(c: i64) -> i64 |
| 73 | func zp_skip_ws(b: *u8, i: i64, n: i64) -> i64 { var j: i64 = i; while j < n { if zp_is_ws(b[j] & 0xff) == 1 { j = j + 1 } else { return j } } return j } |
| 75 | func zp_lit(b: *u8, i: i64, n: i64, lit: *u8) -> i64 |
| 85 | func zp_find(b: *u8, from: i64, n: i64, lit: *u8) -> i64 |
| 100 | func zp_skip_noncode(b: *u8, i: i64, n: i64) -> i64 |
| 131 | func zp_zero_at(b: *u8, i: i64, n: i64) -> i64 |
| 150 | func zp_close(b: *u8, ob: i64, n: i64) -> i64 |
| 162 | func zp_zero_buf(b: *u8, ob: i64, ce: i64, ide: *i64) -> i64 |
| 192 | func zp_digit_at(b: *u8, i: i64, n: i64, ye: *i64) -> i64 |
| 229 | func zp_file(b: *u8, n: i64, ctr: *i64, doapply: i64, out: *u8, nl: *i64, path: *u8) -> i64 |
| 343 | func zp_ends_nx(name: *u8) -> i64 |
| 352 | func zp_join(dir: *u8, name: *u8, out: *u8) -> i64 |
| 361 | func zp_is_dot(name: *u8) -> i64 |
| 367 | func zp_write_atomic(path: *u8, buf: *u8, n: i64) -> i64 |
| 380 | func zp_walk(dir: *u8, ctr: *i64, doapply: i64) -> i64 |
| 420 | func main(argc: i64, argv: **u8) -> i64 |