code wiki / _hdl_build / nx_hget_leak_probe.nx
nx_hget_leak_probe.nx
buildroot/runtime/_hdl_build/nx_hget_leak_probe.nx
about
nx_hget_leak_probe.nx -- MEASURES the per-call allocation leak in ss_hget (2026-07-30).
WHAT IT PROVES: ss_hget used to sys_mmap TWO scratch buffers PER INVOCATION and never free them.
sys_mmap is a real mmap syscall (nx_syscalls.nx:167), not a bump allocator, so the kernel rounds
each to a full page => ~8 KB leaked PER CALL. ss_hget is the hottest read primitive in the tree
(205 call sites; the loaders call it ONCE PER ROW), so the leak scales with ROWS SCANNED, not with
stores opened -- which is why it hid behind the per-open leak everyone was looking at.
THE MEASUREMENT IS THE POINT: run N hgets and read our OWN VSZ before and after. A fixed ss_hget
must show delta_kb == 0 (scratch allocated once, on first call). The pre-fix code would show
roughly N * 8 KB. Reuses nx_leak_check_lib (lc_vsz) rather than re-deriving /proc parsing -- rule 15.
NON-VACUITY: the loop must do REAL work, so the probe seeds a store, reads a key back, and asserts
the VALUE is correct. A probe that measured memory while looking up a missing key would pass while
exercising almost nothing (ss_hget returns early on ns==0, before the allocations).
dependencies 3 imports · 0 importers
imports: nx_syscalls.nxnx_seg_store.nxnx_vsz_watchdog_core.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
| 19 | const HL_MAGIC_1024: i64 = 1024 |
| 21 | const HL_ITERS: i64 = 4000 // enough that a 8KB/call leak is unmissable (~32 MB) |
| 22 | const HL_TOLERANCE_KB: i64 = 64 // page-granular slack; a real leak here is orders of magnitude bigger |
functions
| 24 | func hl_puts(s: *u8) -> i64 |
| 30 | func hl_putn(v: i64) -> i64 |
| 44 | func main() -> i64 |