github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/binary/code.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math" 8 9 "github.com/bananabytelabs/wazero/internal/leb128" 10 "github.com/bananabytelabs/wazero/internal/wasm" 11 ) 12 13 func 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 }