1package binary
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/leb128"
10 "github.com/tetratelabs/wazero/internal/wasm"
11)
12
13func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]wasm.FunctionType, error) {
14 vs, _, err := leb128.DecodeUint32(r)
15 if err != nil {
16 return nil, fmt.Errorf("get size of vector: %w", err)
17 }
18
19 result := make([]wasm.FunctionType, vs)
20 for i := uint32(0); i < vs; i++ {
21 if err = decodeFunctionType(enabledFeatures, r, &result[i]); err != nil {
22 return nil, fmt.Errorf("read %d-th type: %v", i, err)
23 }
24 }
25 return result, nil
26}
27
28// decodeImportSection decodes the decoded import segments plus the count per wasm.ExternType.
29func decodeImportSection(
30 r *bytes.Reader,
31 memorySizer memorySizer,
32 memoryLimitPages uint32,
33 enabledFeatures api.CoreFeatures,
34) (result []wasm.Import,
35 perModule map[string][]*wasm.Import,
36 funcCount, globalCount, memoryCount, tableCount wasm.Index, err error,
37) {
38 vs, _, err := leb128.DecodeUint32(r)
39 if err != nil {
40 err = fmt.Errorf("get size of vector: %w", err)
41 return
42 }
43
44 perModule = make(map[string][]*wasm.Import)
45 result = make([]wasm.Import, vs)
46 for i := uint32(0); i < vs; i++ {
47 imp := &result[i]
48 if err = decodeImport(r, i, memorySizer, memoryLimitPages, enabledFeatures, imp); err != nil {
49 return
50 }
51 switch imp.Type {
52 case wasm.ExternTypeFunc:
53 imp.IndexPerType = funcCount
54 funcCount++
55 case wasm.ExternTypeGlobal:
56 imp.IndexPerType = globalCount
57 globalCount++
58 case wasm.ExternTypeMemory:
59 imp.IndexPerType = memoryCount
60 memoryCount++
61 case wasm.ExternTypeTable:
62 imp.IndexPerType = tableCount
63 tableCount++
64 }
65 perModule[imp.Module] = append(perModule[imp.Module], imp)
66 }
67 return
68}
69
70func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) {
71 vs, _, err := leb128.DecodeUint32(r)
72 if err != nil {
73 return nil, fmt.Errorf("get size of vector: %w", err)
74 }
75
76 result := make([]uint32, vs)
77 for i := uint32(0); i < vs; i++ {
78 if result[i], _, err = leb128.DecodeUint32(r); err != nil {
79 return nil, fmt.Errorf("get type index: %w", err)
80 }
81 }
82 return result, err
83}
84
85func decodeTableSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.Table, error) {
86 vs, _, err := leb128.DecodeUint32(r)
87 if err != nil {
88 return nil, fmt.Errorf("error reading size")
89 }
90 if vs > 1 {
91 if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
92 return nil, fmt.Errorf("at most one table allowed in module as %w", err)
93 }
94 }
95
96 ret := make([]wasm.Table, vs)
97 for i := range ret {
98 err = decodeTable(r, enabledFeatures, &ret[i])
99 if err != nil {
100 return nil, err
101 }
102 }
103 return ret, nil
104}
105
106func decodeMemorySection(
107 r *bytes.Reader,
108 enabledFeatures api.CoreFeatures,
109 memorySizer memorySizer,
110 memoryLimitPages uint32,
111) (*wasm.Memory, error) {
112 vs, _, err := leb128.DecodeUint32(r)
113 if err != nil {
114 return nil, fmt.Errorf("error reading size")
115 }
116 if vs > 1 {
117 return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs)
118 } else if vs == 0 {
119 // memory count can be zero.
120 return nil, nil
121 }
122
123 return decodeMemory(r, enabledFeatures, memorySizer, memoryLimitPages)
124}
125
126func decodeGlobalSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.Global, error) {
127 vs, _, err := leb128.DecodeUint32(r)
128 if err != nil {
129 return nil, fmt.Errorf("get size of vector: %w", err)
130 }
131
132 result := make([]wasm.Global, vs)
133 for i := uint32(0); i < vs; i++ {
134 if err = decodeGlobal(r, enabledFeatures, &result[i]); err != nil {
135 return nil, fmt.Errorf("global[%d]: %w", i, err)
136 }
137 }
138 return result, nil
139}
140
141func decodeExportSection(r *bytes.Reader) ([]wasm.Export, map[string]*wasm.Export, error) {
142 vs, _, sizeErr := leb128.DecodeUint32(r)
143 if sizeErr != nil {
144 return nil, nil, fmt.Errorf("get size of vector: %v", sizeErr)
145 }
146
147 exportMap := make(map[string]*wasm.Export, vs)
148 exportSection := make([]wasm.Export, vs)
149 for i := wasm.Index(0); i < vs; i++ {
150 export := &exportSection[i]
151 err := decodeExport(r, export)
152 if err != nil {
153 return nil, nil, fmt.Errorf("read export: %w", err)
154 }
155 if _, ok := exportMap[export.Name]; ok {
156 return nil, nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name)
157 } else {
158 exportMap[export.Name] = export
159 }
160 }
161 return exportSection, exportMap, nil
162}
163
164func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) {
165 vs, _, err := leb128.DecodeUint32(r)
166 if err != nil {
167 return nil, fmt.Errorf("get function index: %w", err)
168 }
169 return &vs, nil
170}
171
172func decodeElementSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.ElementSegment, error) {
173 vs, _, err := leb128.DecodeUint32(r)
174 if err != nil {
175 return nil, fmt.Errorf("get size of vector: %w", err)
176 }
177
178 result := make([]wasm.ElementSegment, vs)
179 for i := uint32(0); i < vs; i++ {
180 if err = decodeElementSegment(r, enabledFeatures, &result[i]); err != nil {
181 return nil, fmt.Errorf("read element: %w", err)
182 }
183 }
184 return result, nil
185}
186
187func decodeCodeSection(r *bytes.Reader) ([]wasm.Code, error) {
188 codeSectionStart := uint64(r.Len())
189 vs, _, err := leb128.DecodeUint32(r)
190 if err != nil {
191 return nil, fmt.Errorf("get size of vector: %w", err)
192 }
193
194 result := make([]wasm.Code, vs)
195 for i := uint32(0); i < vs; i++ {
196 err = decodeCode(r, codeSectionStart, &result[i])
197 if err != nil {
198 return nil, fmt.Errorf("read %d-th code segment: %v", i, err)
199 }
200 }
201 return result, nil
202}
203
204func decodeDataSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.DataSegment, error) {
205 vs, _, err := leb128.DecodeUint32(r)
206 if err != nil {
207 return nil, fmt.Errorf("get size of vector: %w", err)
208 }
209
210 result := make([]wasm.DataSegment, vs)
211 for i := uint32(0); i < vs; i++ {
212 if err = decodeDataSegment(r, enabledFeatures, &result[i]); err != nil {
213 return nil, fmt.Errorf("read data segment: %w", err)
214 }
215 }
216 return result, nil
217}
218
219func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
220 v, _, err := leb128.DecodeUint32(r)
221 if err != nil && err != io.EOF {
222 // data count is optional, so EOF is fine.
223 return nil, err
224 }
225 return &v, nil
226}