nx_registry_bounds_gate.nx source
↩ module page · 132 lines · 7538 B
1// nx_registry_bounds_gate.nx -- the regression tooth for the reg_index OUT-OF-BOUNDS
2// WRITE root-fixed 2026-07-31 (debt 1785506176).
3//
4// WHAT WENT WRONG: reg_index copied ss_get's length into the caller's buffer and
5// took NO capacity argument, so its signature could not express safety. MEASURED
6// LIVE: the mvault mv:ids index reached ~10.7 MiB (160269 ids x 70B) against a
7// 4 MiB buffer in nx_mvault do_stats -- the vault's own ruler segfaulted and
8// printed NOTHING -- and against an 8 MiB buffer in the /vault browse page.
9//
10// WHY THIS GATE EXISTS: the old defect was invisible to every test that only
11// checked the HAPPY path, because a copy that overruns still returns the right
12// number. So the load-bearing test here is T3/T6: a cap one byte too small must
13// REFUSE and must leave the byte just past the cap UNTOUCHED. That byte is
14// exactly what the pre-fix code clobbered, so this gate is PROVEN ABLE TO FAIL
15// rather than decorative -- revert nx_registry.nx and T3/T6 go red.
16// license_tier: ORIGINAL
17import "nx_registry.nx"
18import "nx_gate.nx"
19import "nx_gate_verdict.nx" // D001: canonical verdict emission + actlog frame
20
21const RB_PFX: *u8 = "knowledge/regbounds-test-\x00"
22const RB_KP: *u8 = "rb:\x00"
23const RB_IDX: *u8 = "rb:__idx__\x00"
24const RB_CANARY: i64 = 171
25
26func main() -> i64 {
27 gw("=== nx_registry_bounds_gate: reg_index refuses rather than overruns ===\n" as *u8)
28 var pass: i64=0; var tot: i64=0
29
30 // Seed a KNOWN index. reg_put is content-idempotent, so re-running this gate
31 // yields the same 12 bytes -- the expected length is derived, not guessed.
32 reg_put(RB_PFX, RB_KP, RB_IDX, "aaa" as *u8, "r1" as *u8, 2)
33 reg_put(RB_PFX, RB_KP, RB_IDX, "bbb" as *u8, "r2" as *u8, 2)
34 reg_put(RB_PFX, RB_KP, RB_IDX, "ccc" as *u8, "r3" as *u8, 2)
35 let want: i64 = 12
36
37 let n_len: i64 = reg_index_len(RB_PFX, RB_IDX)
38 tot=tot+1; if n_len==want { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
39 gw("T1 reg_index_len reports the true length without copying (" as *u8); gn(n_len); gw(")\n" as *u8)
40
41 let big: *u8 = sys_mmap(4096)
42 let n_ok: i64 = reg_index(RB_PFX, RB_IDX, big, 4096)
43 tot=tot+1; if n_ok==want { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
44 gw("T2 an ample cap copies the whole index (" as *u8); gn(n_ok); gw(" bytes)\n" as *u8)
45
46 // ---- THE TOOTH ----------------------------------------------------------
47 // cap is ONE BYTE short. The pre-fix code wrote all 12 bytes regardless, so
48 // buf[11] -- the canary -- was corrupted. Post-fix: refuse, write nothing.
49 let tight: *u8 = sys_mmap(4096)
50 var z: i64=0; while z<64 { tight[z]=RB_CANARY as u8; z=z+1 }
51 let n_ref: i64 = reg_index(RB_PFX, RB_IDX, tight, want - 1)
52 tot=tot+1; if n_ref==(0-1) { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
53 gw("T3 TOOTH a cap one byte short REFUSES with -1 (got " as *u8); gn(n_ref); gw(")\n" as *u8)
54
55 var clean: i64 = 1
56 var c: i64=0; while c<want { if tight[c]!=(RB_CANARY as u8) { clean=0 } c=c+1 }
57 tot=tot+1; if clean==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
58 gw("T4 TOOTH the refused call copied NOTHING -- no partial, no truncation\n" as *u8)
59
60 // Off-by-one guard in the OTHER direction: an exactly-fitting cap must NOT
61 // be refused, or the fix would trade an overflow for a false refusal.
62 let exact: *u8 = sys_mmap(4096)
63 let n_exact: i64 = reg_index(RB_PFX, RB_IDX, exact, want)
64 tot=tot+1; if n_exact==want { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
65 gw("T5 an EXACTLY-fitting cap succeeds (no false refusal)\n" as *u8)
66
67 // Two independent read paths must agree: the bounded copy and the zero-copy
68 // borrow. If they ever diverge, one of them is lying about the store.
69 let po: *i64 = sys_mmap(16) as *i64
70 let lo: *i64 = sys_mmap(16) as *i64
71 let found: i64 = reg_index_open(RB_PFX, RB_IDX, po, lo)
72 var same: i64 = 0
73 if found==1 { if lo[0]==n_ok {
74 same = 1
75 let src: *u8 = po[0] as *u8
76 var i: i64=0; while i<lo[0] { if src[i]!=big[i] { same=0 } i=i+1 }
77 } }
78 tot=tot+1; if same==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
79 gw("T6 zero-copy borrow returns BYTE-IDENTICAL content to the bounded copy\n" as *u8)
80
81 // An absent index is 0, not -1: "empty" and "does not fit" are different
82 // answers and a caller must be able to tell them apart.
83 let miss: i64 = reg_index(RB_PFX, "rb:__nosuchindex__" as *u8, big, 4096)
84 tot=tot+1; if miss==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
85 gw("T7 an ABSENT index returns 0, distinct from the -1 refusal\n" as *u8)
86
87 // ---- SIZE-TO-NEED (reg_index_read) --------------------------------------
88 // The bounded copy above is SAFE but not SUFFICIENT: it needs a capacity the
89 // caller cannot know, and all 18 migrated sites answered with a 1 MiB or 4 MiB
90 // literal. reg_index_read derives the buffer from the index, so these teeth
91 // ask the question a stated capacity can never pass.
92 let rbox: *i64 = sys_mmap(16) as *i64
93 let n_read: i64 = reg_index_read(RB_PFX, RB_IDX, rbox)
94 let rbuf: *u8 = rbox[0] as *u8
95 var ident: i64 = 0
96 if n_read == want {
97 ident = 1
98 var q: i64=0; while q<want { if rbuf[q]!=big[q] { ident=0 } q=q+1 }
99 }
100 tot=tot+1; if ident==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
101 gw("T8 reg_index_read returns BYTE-IDENTICAL content to the bounded copy (" as *u8); gn(n_read); gw(")\n" as *u8)
102
103 // ---- THE TOOTH ----------------------------------------------------------
104 // A capacity one byte short is the WHOLE defect class, at any scale: the live
105 // mv:ids index was 10-12 MiB against a 4 MiB literal, which is this same
106 // relation. T3 proved the bounded call REFUSES here (-1). Size-to-need must
107 // SUCCEED on the identical index -- otherwise the migration merely traded a
108 // corrupt read for a failed one. Derived from `want`, so it cannot silently
109 // stop being a violation.
110 let tight2: *u8 = sys_mmap(4096)
111 let n_capped: i64 = reg_index(RB_PFX, RB_IDX, tight2, want - 1)
112 tot=tot+1; if n_capped==(0-1) { if n_read==want { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
113 gw("T9 TOOTH a stated capacity FAILS (" as *u8); gn(n_capped); gw(") where size-to-need SUCCEEDS (" as *u8); gn(n_read); gw(")\n" as *u8)
114
115 // neg-control-absent: absent must be 0 with a usable empty buffer, NEVER -1.
116 // Every measured caller assigns this straight into `while i <= n`, so a -1
117 // here would not merely mislead -- it would skip the loop and report empty.
118 let abox: *i64 = sys_mmap(16) as *i64
119 let n_abs: i64 = reg_index_read(RB_PFX, "rb:__nosuchindex__" as *u8, abox)
120 let abuf: *u8 = abox[0] as *u8
121 var absok: i64 = 0
122 if n_abs == 0 { if abox[0] != 0 { if abuf[0] == (0 as u8) { absok = 1 } } }
123 tot=tot+1; if absok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
124 gw("T10 neg-control-absent: absent reads 0 with a valid empty buffer, never -1\n" as *u8)
125
126 let ctr: *i64 = gv_ctr()
127 ctr[0] = pass
128 ctr[1] = tot
129 let rc: i64 = gv_verdict("REGINDEX-BOUNDS" as *u8, ctr, "reg_index is bounded, refuses rather than truncating, and both read paths agree" as *u8)
130 sys_exit(rc)
131 return rc
132}