code.go

  1package binary
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"io"
  7	"math"
  8
  9	"github.com/tetratelabs/wazero/internal/leb128"
 10	"github.com/tetratelabs/wazero/internal/wasm"
 11)
 12
 13func decodeCode(r *bytes.Reader, codeSectionStart uint64, ret *wasm.Code) (err error) {
 14	ss, _, err := leb128.DecodeUint32(r)
 15	if err != nil {
 16		return fmt.Errorf("get the size of code: %w", err)
 17	}
 18	remaining := int64(ss)
 19
 20	// Parse #locals.
 21	ls, bytesRead, err := leb128.DecodeUint32(r)
 22	remaining -= int64(bytesRead)
 23	if err != nil {
 24		return fmt.Errorf("get the size locals: %v", err)
 25	} else if remaining < 0 {
 26		return io.EOF
 27	}
 28
 29	// Validate the locals.
 30	bytesRead = 0
 31	var sum uint64
 32	for i := uint32(0); i < ls; i++ {
 33		num, n, err := leb128.DecodeUint32(r)
 34		if err != nil {
 35			return fmt.Errorf("read n of locals: %v", err)
 36		} else if remaining < 0 {
 37			return io.EOF
 38		}
 39
 40		sum += uint64(num)
 41
 42		b, err := r.ReadByte()
 43		if err != nil {
 44			return fmt.Errorf("read type of local: %v", err)
 45		}
 46
 47		bytesRead += n + 1
 48		switch vt := b; vt {
 49		case wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeI64, wasm.ValueTypeF64,
 50			wasm.ValueTypeFuncref, wasm.ValueTypeExternref, wasm.ValueTypeV128:
 51		default:
 52			return fmt.Errorf("invalid local type: 0x%x", vt)
 53		}
 54	}
 55
 56	if sum > math.MaxUint32 {
 57		return fmt.Errorf("too many locals: %d", sum)
 58	}
 59
 60	// Rewind the buffer.
 61	_, err = r.Seek(-int64(bytesRead), io.SeekCurrent)
 62	if err != nil {
 63		return err
 64	}
 65
 66	localTypes := make([]wasm.ValueType, 0, sum)
 67	for i := uint32(0); i < ls; i++ {
 68		num, bytesRead, err := leb128.DecodeUint32(r)
 69		remaining -= int64(bytesRead) + 1 // +1 for the subsequent ReadByte
 70		if err != nil {
 71			return fmt.Errorf("read n of locals: %v", err)
 72		} else if remaining < 0 {
 73			return io.EOF
 74		}
 75
 76		b, err := r.ReadByte()
 77		if err != nil {
 78			return fmt.Errorf("read type of local: %v", err)
 79		}
 80
 81		for j := uint32(0); j < num; j++ {
 82			localTypes = append(localTypes, b)
 83		}
 84	}
 85
 86	bodyOffsetInCodeSection := codeSectionStart - uint64(r.Len())
 87	body := make([]byte, remaining)
 88	if _, err = io.ReadFull(r, body); err != nil {
 89		return fmt.Errorf("read body: %w", err)
 90	}
 91
 92	if endIndex := len(body) - 1; endIndex < 0 || body[endIndex] != wasm.OpcodeEnd {
 93		return fmt.Errorf("expr not end with OpcodeEnd")
 94	}
 95
 96	ret.BodyOffsetInCodeSection = bodyOffsetInCodeSection
 97	ret.LocalTypes = localTypes
 98	ret.Body = body
 99	return nil
100}