nx_read_file_gate.nx
buildroot/runtime/nx_read_file_gate.nx
about
nx_read_file_gate.nx -- referee for sys_read_file / sys_free_file, the estate's whole-file reader.
WHY (debt 1787076780, measured 2026-08-17/19): for a file whose size is UNKNOWABLE (lseek END <= 0 --
/proc files, pipes, and every EMPTY regular file, which reports 0 just the same) the reader reserved
4 GiB of address space per call and the paired free could release only what was read. A daemon that
read an empty registry every sweep ballooned its VmSize by 4 GiB per read; the leak screens flagged it.
2026-08-19 the size-unknowable path GROWS (64 KiB window, doubling, exact hand-back). These teeth pin:
T1 a known-size file reads whole and byte-exact (the path the compiler itself uses -- unchanged)
T2 an EMPTY regular file returns a non-NULL buffer with len 0 (present-and-empty is not absent)
T3 THE BITE: reading + freeing an empty file 32 times moves VmSize by < 1 MiB (the old reader grew
by 4 GiB per read -- 128 GiB here -- and could not shrink back)
T4 a size-unknowable /proc file reads whole (procs_blocked, the LAST line of /proc/stat, is present)
T5 a size-unknowable file LARGER than the first window (/proc/kallsyms, MBs) reads whole through the
doubling path -- precondition: readable on this kernel; SKIP otherwise, never RED
T6 sys_free_file on the exact mapping returns 0 (munmap success) and an absent path returns NULL/0
T7 neg-control: the free of NULL is a no-op (returns 0, never a crash)
license_tier: ORIGINAL expect_exit: 0
dependencies 2 imports · 0 importers
imports: nx_gate_verdict.nxnx_resmon_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 21 | const RF_FIX_DIR: *u8 = "/tmp/nx_read_file_gate" |
| 22 | const RF_FIX_EMPTY: *u8 = "/tmp/nx_read_file_gate/empty.bin" |
| 23 | const RF_FIX_KNOWN: *u8 = "/tmp/nx_read_file_gate/known.bin" |
| 24 | const RF_FIX_ABSENT: *u8 = "/tmp/nx_read_file_gate/does-not-exist.bin" |
| 25 | const RF_KNOWN_BYTES: i64 = 100003 // odd, past a page and past any arena cell: the known-size path |
| 26 | const RF_EMPTY_ROUNDS: i64 = 32 // 32 x 4 GiB would be 128 GiB under the old reader |
| 27 | const RF_VMSIZE_TOL_KB: i64 = 1024 // 1 MiB of VmSize drift tolerated across the 32 rounds (arena cells, page rounding) |
| 28 | const RF_STATUS_CAP: i64 = 8192 |
| 29 | const RF_PROC_STAT: *u8 = "/proc/stat" |
| 30 | const RF_PROC_BIG: *u8 = "/proc/kallsyms" |
| 31 | const RF_MODE_0644: i64 = 420 |
functions
| 33 | func rf_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: rf_contains |
| 34 | func rf_vmsize_kb() -> i64 |
| 40 | func rf_contains(buf: *u8, n: i64, pat: *u8) -> i64 |
| 52 | func rf_write_known() -> i64 called by 1: main |
| 64 | func main(argc: i64, argv: *i64) -> i64 |