code wiki / _hdl_build / _simsize_gate.nx
_simsize_gate.nx
buildroot/runtime/_hdl_build/_simsize_gate.nx
about
_simsize_gate.nx -- STRUCT-SIZE-vs-ALLOCATION gate. NO mocks.
WHY THIS EXISTS (measured 2026-08-07): FIFTEEN live sources allocated NxRv64imSim with a
hardcoded `sys_mmap(128)`. 128 bytes is 16 i64 slots; the struct had grown to 26 fields = 208
bytes. So `halted` (offset 128), `halt_code` (136) and `steps` (144) -- THE THREE FIELDS EVERY
BOOT VERDICT IS COMPUTED FROM -- were written and read OUT OF BOUNDS. It hid for months inside
4 KiB page slack and surfaced only when NXA_SMALL_MAX went 64 -> 256 and a 128-byte request began
being served from the shared small arena, landing the overrun on a live neighbour. The symptom
was nx_boot_run_sov reporting steps=1953655343 = 0x74726976 = the ASCII "virt" of the virtio
magic the driver under test had just read.
A HARDCODED BYTE SIZE FOR A STRUCT THAT KEEPS GROWING IS AN OUT-OF-BOUNDS WRITE ON A TIMER.
The remedy is not a bigger number -- a bigger number just resets the timer. The remedy is a
RULER: re-derive the field count FROM SOURCE on every run and refuse if the declared allocation
constant cannot hold it.
T1 REAL -- NxRv64imSim fields*8 <= NX_RV64IM_SIM_BYTES, BOTH parsed from rv64im_min_sim.nx.
T2 NEG CTL -- a fixture whose struct provably does NOT fit its constant must be REFUSED.
Without this tooth the gate would score its loudest PASS when it parsed nothing.
T3 PARSER -- a fixture with a KNOWN field count must return EXACTLY that count. T1+T2 alone
are both satisfied by a parser that always returns 0; this tooth kills that.
Evidence -> knowledge/status/simsize.log (SIMSIZEGATE row). Sovereign. license_tier: ORIGINAL
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 32 | const SG_SRC: *u8 = "buildroot/runtime/_hdl_build/rv64im_min_sim.nx" |
| 33 | const SG_SRC_ALT: *u8 = "runtime/_hdl_build/rv64im_min_sim.nx" |
| 34 | const SG_FIX: *u8 = "/tmp/_simsize_fixture.nx" |
| 35 | const SG_LOG: *u8 = "knowledge/status/simsize.log" |
| 36 | const SG_CAP: i64 = 262144 |
functions
| 38 | func sg_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } calls 1: sys_write |
| 39 | func sg_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 } |
| 46 | func sg_fn(fd: i64, v: i64) -> i64 |
| 63 | func sg_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } |
| 65 | func sg_read(path: *u8, buf: *u8, cap: i64) -> i64 |
| 80 | func sg_find(buf: *u8, n: i64, pat: *u8, pl: i64, from: i64) -> i64 |
| 98 | func sg_struct_fields(buf: *u8, n: i64, sname: *u8) -> i64 |
| 164 | func sg_const_val(buf: *u8, n: i64, cname: *u8) -> i64 |
| 209 | func sg_write_fixture() -> i64 |
| 225 | func main() -> i64 |