nx_wasm_vm_bounds_gate_20260912.nx source
↩ module page · 98 lines · 6107 B
1import "nx_wasm_vm_bounds_20260912.nx"
2import "nx_gate_verdict.nx"
3// Regression sizes deliberately cross all three old fixed metadata allocations.
4const WG_TYPES: i64 = 1024 + 1
5const WG_FUNCS: i64 = 2048 + 1
6const WG_EXPORTS: i64 = 1092
7func wg_u32(b: *u8, p: i64, value: i64) -> i64 {
8 var v: i64 = value; var o: i64 = p; var go: i64 = 1
9 while go == 1 { var x: i64 = v & 127; v = v >> 7; if v != 0 { x = x | 128 }; b[o] = x as u8; o = o + 1; if v == 0 { go = 0 } }
10 return o
11}
12func wg_name(b: *u8, p: i64, value: i64) -> i64 {
13 var o: i64 = p; b[o] = 102 as u8; o = o + 1
14 var divisor: i64 = 1
15 while value / divisor >= 10 { divisor = divisor * 10 }
16 while divisor > 0 { b[o] = (48 + ((value / divisor) % 10)) as u8; o = o + 1; divisor = divisor / 10 }
17 b[o] = 0 as u8; return o - p
18}
19func wg_section(b: *u8, p: i64, sid: i64, payload: *u8, size: i64, start: *i64) -> i64 {
20 b[p] = sid as u8; var o: i64 = wg_u32(b, p + 1, size); start[0] = o
21 var i: i64 = 0; while i < size { b[o] = payload[i]; o = o + 1; i = i + 1 }; return o
22}
23func wg_image(b: *u8, marks: *i64) -> i64 {
24 b[0] = 0 as u8; b[1] = 97 as u8; b[2] = 115 as u8; b[3] = 109 as u8
25 b[4] = 1 as u8; b[5] = 0 as u8; b[6] = 0 as u8; b[7] = 0 as u8
26 let payload: *u8 = sys_mmap((WG_TYPES + WG_FUNCS + WG_EXPORTS) * 16)
27 let start: *i64 = sys_mmap(8) as *i64; var o: i64 = 8
28 var p: i64 = wg_u32(payload, 0, WG_TYPES); var i: i64 = 0
29 while i < WG_TYPES { payload[p] = 96 as u8; payload[p+1] = 0 as u8; payload[p+2] = 1 as u8; payload[p+3] = 126 as u8; p = p + 4; i = i + 1 }
30 o = wg_section(b, o, 1, payload, p, start)
31 p = wg_u32(payload, 0, WG_FUNCS); marks[0] = p; i = 0
32 while i < WG_FUNCS { p = wg_u32(payload, p, WG_TYPES - 1); i = i + 1 }
33 o = wg_section(b, o, 3, payload, p, start); marks[0] = marks[0] + start[0]
34 p = wg_u32(payload, 0, WG_EXPORTS); let name: *u8 = sys_mmap(32); i = 0
35 while i < WG_EXPORTS {
36 let nl: i64 = wg_name(name, 0, i); p = wg_u32(payload, p, nl)
37 var j: i64 = 0; while j < nl { payload[p] = name[j]; p = p + 1; j = j + 1 }
38 payload[p] = 0 as u8; p = p + 1
39 p = wg_u32(payload, p, WG_FUNCS - 1); i = i + 1
40 }
41 o = wg_section(b, o, 7, payload, p, start); marks[1] = start[0]
42 p = wg_u32(payload, 0, WG_FUNCS); i = 0
43 while i < WG_FUNCS { payload[p] = 4 as u8; payload[p+1] = 0 as u8; payload[p+2] = 66 as u8; payload[p+3] = 7 as u8; payload[p+4] = 11 as u8; p = p + 5; i = i + 1 }
44 o = wg_section(b, o, 10, payload, p, start); marks[2] = start[0]
45 return o
46}
47func wg_refuse(b: *u8, n: i64, label: *u8, ctr: *i64) -> i64 {
48 let m: *WasmMod = wm_new(b, n)
49 let rc: i64 = wm_parse(m)
50 gv_check(label, rc < 0 && (m.exp_name_off as i64) == 0 && (m.type_nparam as i64) == 0 && (m.func_type as i64) == 0 && m.n_exports == 0 && m.n_funcs == 0 && m.n_types == 0, ctr)
51 return rc
52}
53func main() -> i64 {
54 let ctr: *i64 = gv_ctr(); gv_head("WASM-METADATA-BOUNDS")
55 let b: *u8 = sys_mmap((WG_TYPES + WG_FUNCS + WG_EXPORTS) * 32)
56 let marks: *i64 = sys_mmap(24) as *i64
57 let n: i64 = wg_image(b, marks)
58 let m: *WasmMod = wm_new(b, n); let rc: i64 = wm_parse(m)
59 gv_check("valid counts exceed all old metadata caps", rc == 0 && m.n_types == WG_TYPES && m.n_funcs == WG_FUNCS && m.n_exports == WG_EXPORTS, ctr)
60 if rc == 0 {
61 gv_check("last function retains high type index", m.func_type[WG_FUNCS-1] == WG_TYPES-1 && m.type_nres[WG_TYPES-1] == 1, ctr)
62 gv_check("late export resolves beyond old1024 bound", wm_find_export(m, "f1091") == WG_FUNCS-1, ctr)
63 gv_check("late export executes last function", wm_run(m, "f1091", 0, 0, 0, 0, 0, 0) == 7, ctr)
64 }
65 wg_refuse(b, 7, "short header refuses before metadata writes", ctr)
66 let version: u8 = b[4]; b[4] = 2 as u8
67 wg_refuse(b, n, "unsupported version refuses before metadata writes", ctr); b[4] = version
68 wg_refuse(b, n - 1, "truncated section refuses before metadata writes", ctr)
69 let ft: i64 = marks[0]; let old_type: u8 = b[ft+1]; b[ft+1] = 127 as u8
70 wg_refuse(b, n, "invalid function type index refuses before metadata writes", ctr); b[ft+1] = old_type
71 let ex: i64 = marks[1]; let ex0: u8 = b[ex]; let ex1: u8 = b[ex+1]
72 wg_u32(b, ex, WG_EXPORTS + WG_FUNCS * 16)
73 wg_refuse(b, n, "export count larger than section refuses before writes", ctr); b[ex] = ex0; b[ex+1] = ex1
74 // Rebuild because the inflated LEB intentionally extends into the first name byte.
75 wg_image(b, marks)
76 let cd: i64 = marks[2]; let old_code: u8 = b[cd]; b[cd] = (old_code - (1 as u8)) as u8
77 wg_refuse(b, n, "code/function count mismatch refuses before metadata writes", ctr); b[cd] = old_code
78 // A name length that crosses its export-section boundary must never reach table writes.
79 let name_at: i64 = marks[1] + 2
80 let saved_name0: u8 = b[name_at]; let saved_name1: u8 = b[name_at+1]; let saved_name2: u8 = b[name_at+2]
81 wg_u32(b, name_at, n)
82 wg_refuse(b, n, "export name exceeding section refuses before metadata writes", ctr)
83 b[name_at] = saved_name0; b[name_at+1] = saved_name1; b[name_at+2] = saved_name2
84 let body_at: i64 = marks[2] + 2; let body_size: u8 = b[body_at]
85 b[body_at] = 1 as u8
86 wg_refuse(b, n, "body too short for locals and end refuses before writes", ctr)
87 b[body_at] = body_size
88 wg_refuse(0 as *u8, 8, "null image refuses before header reads", ctr)
89 let z: *u8 = sys_mmap(16); var zi: i64 = 0
90 while zi < 8 { z[zi] = b[zi]; zi = zi + 1 }
91 z[8] = 1 as u8; z[9] = 128 as u8
92 wg_refuse(z, 10, "truncated unsigned LEB refuses before metadata writes", ctr)
93 z[9] = 255 as u8; z[10] = 255 as u8; z[11] = 255 as u8; z[12] = 255 as u8; z[13] = 31 as u8
94 wg_refuse(z, 14, "u32 LEB overflow refuses before metadata writes", ctr)
95 let empty: *WasmMod = wm_new(z, 8)
96 gv_check("empty valid module remains accepted", wm_parse(empty) == 0 && empty.n_exports == 0, ctr)
97 return gv_verdict("WASM-METADATA-BOUNDS", ctr, "Metadata bounds only; bytecode instruction validation and live Beach interaction separate.")
98}