nx_wasm_memory_lib.nx source
↩ module page · 100 lines · 3333 B
1// Allocation-free inspection of Nishi's single-memory Wasm artifacts.
2// This reads the memory contract only; it is not a full Wasm validator.
3const WM_U32_BITS: i64=32
4const WM_LEB_BITS: i64=7
5const WM_U32_MAX: i64=4294967295
6const WM_PAGE_MAX: i64=65536
7const WM_HEADER: i64=8
8const WM_FIELDS: i64=4 // minimum pages, maximum (-1 absent), shared, imported.
9struct WMemReader { b: *u8, end: i64, at: i64, error: i64 }
10func wmem_byte(r: *WMemReader) -> i64 {
11 if r.error<0 { return 0 }
12 if r.at>=r.end { r.error=0-1; return 0 }
13 let v: i64=r.b[r.at] as i64
14 r.at=r.at+1
15 return v
16}
17func wmem_u32(r: *WMemReader) -> i64 {
18 var value: i64=0
19 var shift: i64=0
20 while shift<WM_U32_BITS {
21 let b: i64=wmem_byte(r)
22 if r.error<0 { return 0 }
23 let payload: i64=b&127
24 if payload>(WM_U32_MAX>>shift) { r.error=0-2;return 0 }
25 value=value|(payload<<shift)
26 if (b&128)==0 { return value }
27 shift=shift+WM_LEB_BITS
28 }
29 r.error=0-2
30 return 0
31}
32func wmem_name(r: *WMemReader) -> i64 {
33 let n: i64=wmem_u32(r)
34 if n>r.end-r.at { r.error=0-1;return 0 }
35 r.at=r.at+n
36 return 0
37}
38func wmem_limits(r: *WMemReader,out: *i64,imported: i64) -> i64 {
39 let flags: i64=wmem_u32(r)
40 if flags!=0 { if flags!=1 { if flags!=3 { r.error=0-3;return 0 } } }
41 let low: i64=wmem_u32(r)
42 var high: i64=0-1
43 if (flags&1)!=0 { high=wmem_u32(r) }
44 if r.error<0 { return 0 }
45 if low>WM_PAGE_MAX { r.error=0-4;return 0 }
46 if high>WM_PAGE_MAX { r.error=0-4;return 0 }
47 if high>=0 { if high<low { r.error=0-4;return 0 } }
48 out[0]=low;out[1]=high;out[2]=(flags>>1)&1;out[3]=imported
49 return 0
50}
51func wmem_read(b: *u8,n: i64,out: *i64) -> i64 {
52 if n<WM_HEADER { return 0-1 }
53 if b[0]!=(0 as u8) { return 0-5 }
54 if b[1]!=(97 as u8) { return 0-5 }
55 if b[2]!=(115 as u8) { return 0-5 }
56 if b[3]!=(109 as u8) { return 0-5 }
57 if b[4]!=(1 as u8) { return 0-5 }
58 if b[5]!=(0 as u8) { return 0-5 }
59 if b[6]!=(0 as u8) { return 0-5 }
60 if b[7]!=(0 as u8) { return 0-5 }
61 var r: WMemReader
62 r.b=b;r.at=WM_HEADER;r.end=n;r.error=0
63 var found: i64=0
64 while r.at<n {
65 let section: i64=wmem_byte(&r)
66 let size: i64=wmem_u32(&r)
67 if r.error<0 { return r.error }
68 if size>n-r.at { return 0-1 }
69 let end: i64=r.at+size
70 r.end=end
71 if section==2 {
72 let count: i64=wmem_u32(&r)
73 var i: i64=0
74 while i<count {
75 wmem_name(&r);wmem_name(&r)
76 let kind: i64=wmem_byte(&r)
77 if r.error<0 { return r.error }
78 if kind==0 { wmem_u32(&r) } else {
79 if kind!=2 { return 0-6 }
80 if found!=0 { return 0-7 }
81 wmem_limits(&r,out,1);found=1
82 }
83 if r.error<0 { return r.error }
84 i=i+1
85 }
86 if r.at!=end { return 0-8 }
87 }
88 if section==5 {
89 let count: i64=wmem_u32(&r)
90 if count!=1 { return 0-7 }
91 if found!=0 { return 0-7 }
92 wmem_limits(&r,out,0);found=1
93 if r.error<0 { return r.error }
94 if r.at!=end { return 0-8 }
95 }
96 r.at=end;r.end=n
97 }
98 if found==0 { return 0-9 }
99 return 0
100}