func (uls UnknownLoaders) Load(r reader.Reader, payloadLen uint32) (err error) { defer func() { err = errutil.ErrorOrPanic(recover()) }() load := loader.L{r} nameLen := load.Varuint32() if nameLen > maxSectionNameLen { panic(errors.New("unknown section name is too long")) } name := string(load.Bytes(nameLen)) if f := uls[name]; f != nil { if err := f(name, load); err != nil { panic(err) } } else { if _, err := io.CopyN(ioutil.Discard, load, int64(payloadLen)); err != nil { panic(err) } } return }
func (ns *NameSection) Load(_ string, r reader.Reader) (err error) { defer func() { err = errutil.ErrorOrPanic(recover()) }() load := loader.L{r} count := load.Varuint32() ns.FunctionNames = make([]FunctionName, count) for i := range ns.FunctionNames { fn := &ns.FunctionNames[i] funNameLen := load.Varuint32() fn.FunName = string(load.Bytes(funNameLen)) localCount := load.Varuint32() fn.LocalNames = make([]string, localCount) for j := range fn.LocalNames { localNameLen := load.Varuint32() fn.LocalNames[j] = string(load.Bytes(localNameLen)) } } return }
func (m *Module) genData(load loader.L) { if debug { debugf("data section") debugDepth++ } if m.memoryOffset&15 != 0 { // not 16-byte aligned? (assume at least 8-byte alignment.) n := len(m.globals) m.globals = append(m.globals, global{}) m.data = appendGlobalsData(m.data, m.globals[n:]) m.memoryOffset = len(m.data) } for i := range load.Count() { if debug { debugf("data segment") debugDepth++ } if index := load.Varuint32(); index != 0 { panic(fmt.Errorf("unsupported memory index: %d", index)) } offset := readOffsetInitExpr(load, m) size := load.Varuint32() needMemorySize := int64(offset) + int64(size) if needMemorySize >= int64(m.memoryLimits.initial) { panic(fmt.Errorf("memory segment #%d exceeds initial memory size", i)) } needDataSize := int64(m.memoryOffset) + needMemorySize if needDataSize > int64(len(m.data)) { if int64(cap(m.data)) >= needDataSize { m.data = m.data[:needDataSize] } else { buf := make([]byte, needDataSize) copy(buf, m.data) m.data = buf } } dataOffset := m.memoryOffset + int(offset) load.Into(m.data[dataOffset:needDataSize]) if debug { debugDepth-- debugf("data segmented: offset=0x%x size=0x%x", offset, size) } } if debug { debugDepth-- debugf("data sectioned") } }
func readSectionHeader(load loader.L, expectId byte, idError string) (ok bool) { id, err := load.ReadByte() if err != nil { if err == io.EOF { return } panic(err) } if id != expectId { panic(errors.New(idError)) } load.Varuint32() // payload len ok = true return }
func copySection(w io.Writer, r reader.Reader, expectId byte) (ok bool) { store := storer{w} load := loader.L{Reader: r} loop: for { id, err := load.ReadByte() if err != nil { if err == io.EOF { return } panic(err) } switch { case id == sectionids.Unknown: payloadLen := load.Varuint32() if _, err := io.CopyN(ioutil.Discard, load, int64(payloadLen)); err != nil { panic(err) } case id == expectId: store.Byte(id) break loop default: load.UnreadByte() return } } payloadLen := load.Varuint32() store.Varuint32(payloadLen) if _, err := io.CopyN(store, load, int64(payloadLen)); err != nil { panic(err) } ok = true return }
func readResizableLimits(load loader.L, maxInitial, maxMaximum uint32, scale int) resizableLimits { flags := load.Varuint32() initial := load.Varuint32() if initial > maxInitial { panic(fmt.Errorf("initial memory size is too large: %d", initial)) } maximum := maxMaximum if (flags & resizableLimitsFlagMaximum) != 0 { maximum = load.Varuint32() if maximum > maxMaximum { maximum = maxMaximum } if maximum < initial { panic(fmt.Errorf("maximum memory size %d is smaller than initial memory size %d", maximum, initial)) } } return resizableLimits{int(initial) * scale, int(maximum) * scale, true} }
func (m moduleLoader) loadUntil(load loader.L, untilSection byte) byte { var header struct { MagicNumber uint32 Version uint32 } if err := binary.Read(load, binary.LittleEndian, &header); err != nil { panic(err) } if header.MagicNumber != moduleMagicNumber { panic(errors.New("not a WebAssembly module")) } if header.Version != moduleVersion { panic(fmt.Errorf("unsupported module version: %d", header.Version)) } var skipSection func(byte, uint32) error if m.UnknownSectionLoader != nil { skipSection = func(id byte, payloadLen uint32) (err error) { if id == sectionids.Unknown { err = m.UnknownSectionLoader(load, payloadLen) } else { _, err = io.CopyN(ioutil.Discard, load, int64(payloadLen)) } return } } else { skipSection = func(id byte, payloadLen uint32) (err error) { _, err = io.CopyN(ioutil.Discard, load, int64(payloadLen)) return } } var seenId byte for { id, err := load.ReadByte() if err != nil { if err == io.EOF { return 0 } panic(err) } if id != sectionids.Unknown { if id <= seenId { panic(fmt.Errorf("section 0x%x follows section 0x%x", id, seenId)) } seenId = id } if id >= untilSection { load.UnreadByte() return id } payloadLen := load.Varuint32() if f := sectionLoaders[id]; f != nil { f(m, load) } else if err := skipSection(id, payloadLen); err != nil { panic(err) } } }
func readInitExpr(load loader.L, m *Module) (valueBits uint64, t types.T) { op := opcode(load.Byte()) switch op { case opcodeI32Const: valueBits = uint64(int64(load.Varint32())) t = types.I32 case opcodeI64Const: valueBits = uint64(load.Varint64()) t = types.I64 case opcodeF32Const: valueBits = uint64(load.Uint32()) t = types.F32 case opcodeF64Const: valueBits = load.Uint64() t = types.F64 case opcodeGetGlobal: i := load.Varuint32() if i >= uint32(m.numImportGlobals) { panic(fmt.Errorf("import global index out of bounds in initializer expression: %d", i)) } g := m.globals[i] valueBits = g.init t = g.t default: panic(fmt.Errorf("unsupported operation in initializer expression: %s", op)) } if op := opcode(load.Byte()); op != opcodeEnd { panic(fmt.Errorf("unexpected operation in initializer expression when expecting end: %s", op)) } return }