section.go

  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}