Skip to content
This repository was archived by the owner on May 11, 2020. It is now read-only.

disasm: Fix referencing the incorrect function type in call_indirect #51

Merged
merged 12 commits into from
Apr 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions disasm/disasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,16 @@ type StackInfo struct {
type BlockInfo struct {
Start bool // If true, this instruction starts a block. Else this instruction ends it.
Signature wasm.BlockType // The block signature
// The index to the accompanying control operator.
// For 'if', this is an index to the 'else' operator
// For else/loop/block, the index is to the 'end' operator
PairIndex int

// Indices to the accompanying control operator.
// For 'if', this is the index to the 'else' operator.
IfElseIndex int
// For 'else', this is the index to the 'if' operator.
ElseIfIndex int
// The index to the `end' operator for if/else/loop/block.
EndIndex int
// For end, it is the index to the operator that starts the block.
BlockStartIndex int
}

// Disassembly is the result of disassembling a WebAssembly function.
Expand Down Expand Up @@ -133,7 +139,7 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
instr.Unreachable = !isInstrReachable(blockPolymorphicOps)
}

logger.Printf("op: %s, ureachable: %v", opStr.Name, instr.Unreachable)
logger.Printf("op: %s, unreachable: %v", opStr.Name, instr.Unreachable)
if !opStr.Polymorphic && !instr.Unreachable {
top := int(stackDepths.Top())
top -= len(opStr.Args)
Expand All @@ -157,7 +163,7 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
}
case ops.Select:
if !instr.Unreachable {
stackDepths.SetTop(stackDepths.Top() - 3)
stackDepths.SetTop(stackDepths.Top() - 2)
}
case ops.Return:
if !instr.Unreachable {
Expand All @@ -173,10 +179,14 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
instr.Block = &BlockInfo{
Start: false,
Signature: blockSig,
PairIndex: int(blockStartIndex),
}

disas.Code[blockStartIndex].Block.PairIndex = curIndex
if op == ops.End {
instr.Block.BlockStartIndex = int(blockStartIndex)
disas.Code[blockStartIndex].Block.EndIndex = curIndex
} else { // ops.Else
instr.Block.ElseIfIndex = int(blockStartIndex)
disas.Code[blockStartIndex].Block.IfElseIndex = int(blockStartIndex)
}

// The max depth reached while execing the last block
// If the signature of the current block is not empty,
Expand All @@ -201,10 +211,12 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
StackTopDiff: int64(elemsDiscard),
PreserveTop: blockSig != wasm.BlockTypeEmpty,
}
logger.Printf("discard %d elements, preserve top: %v", elemsDiscard, instr.NewStack.PreserveTop)
} else {
instr.NewStack = &StackInfo{}
}

logger.Printf("setting new stack for %s block (%d)", disas.Code[blockStartIndex].Op.Name, blockStartIndex)
disas.Code[blockStartIndex].NewStack = instr.NewStack
if !instr.Unreachable {
blockPolymorphicOps = blockPolymorphicOps[:len(blockPolymorphicOps)-1]
Expand Down Expand Up @@ -351,10 +363,19 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
instr.Immediates = append(instr.Immediates, reserved)
}
if !instr.Unreachable {
fn := module.GetFunction(int(index))
var sig *wasm.FunctionSig
top := int(stackDepths.Top())
top -= len(fn.Sig.ParamTypes)
top += len(fn.Sig.ReturnTypes)
if op == ops.CallIndirect {
if module.Types == nil {
return nil, errors.New("missing types section")
}
sig = &module.Types.Entries[index]
top--
} else {
sig = module.GetFunction(int(index)).Sig
}
top -= len(sig.ParamTypes)
top += len(sig.ReturnTypes)
stackDepths.SetTop(uint64(top))
disas.checkMaxDepth(top)
}
Expand Down Expand Up @@ -438,5 +459,11 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
curIndex++
}

if logging {
for _, instr := range disas.Code {
logger.Printf("%v %v", instr.Op.Name, instr.NewStack)
}
}

return disas, nil
}
17 changes: 12 additions & 5 deletions disasm/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@ import (
"os"
)

var PrintDebugInfo = false

var logger *log.Logger
var (
logger *log.Logger
logging bool
)

func init() {
func SetDebugMode(l bool) {
w := ioutil.Discard
logging = l

if PrintDebugInfo {
if l {
w = os.Stderr
}

logger = log.New(w, "", log.Lshortfile)
logger.SetFlags(log.Lshortfile)

}

func init() {
SetDebugMode(false)
}
4 changes: 2 additions & 2 deletions exec/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package exec
import "errors"

func (vm *VM) doCall(compiled compiledFunction, index int64) {
newStack := make([]uint64, compiled.maxDepth)
newStack := make([]uint64, 0, compiled.maxDepth)
locals := make([]uint64, compiled.totalLocalVars)

for i := compiled.args - 1; i >= 0; i-- {
Expand Down Expand Up @@ -81,5 +81,5 @@ func (vm *VM) callIndirect() {
}
}

vm.doCall(vm.compiledFuncs[elemIndex], int64(index))
vm.doCall(vm.compiledFuncs[elemIndex], int64(elemIndex))
}
9 changes: 5 additions & 4 deletions exec/internal/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,15 @@ func Compile(disassembly []disasm.Instr) ([]byte, []*BranchTable) {
}
continue
case ops.Else:
// add code for jumping out of a taken if branch
if instr.NewStack != nil && instr.NewStack.StackTopDiff != 0 {
if instr.NewStack.PreserveTop {
ifInstr := disassembly[instr.Block.ElseIfIndex] // the corresponding `if` instruction for this else
if ifInstr.NewStack != nil && ifInstr.NewStack.StackTopDiff != 0 {
// add code for jumping out of a taken if branch
if ifInstr.NewStack.PreserveTop {
buffer.WriteByte(OpDiscardPreserveTop)
} else {
buffer.WriteByte(OpDiscard)
}
binary.Write(buffer, binary.LittleEndian, instr.NewStack.StackTopDiff)
binary.Write(buffer, binary.LittleEndian, ifInstr.NewStack.StackTopDiff)
}
buffer.WriteByte(OpJmp)
ifBlockEndOffset := int64(buffer.Len())
Expand Down
Binary file added exec/testdata/bug-49.wasm
Binary file not shown.
10 changes: 10 additions & 0 deletions exec/testdata/modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -1106,5 +1106,15 @@
"return": "i32:0"
}
]
},
{
"file": "bug-49.wasm",
"tests": [
{
"function": "sample",
"args": [],
"trap": "i32:1"
}
]
}
]
5 changes: 2 additions & 3 deletions exec/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,8 @@ func (vm *VM) ExecCode(fnIndex int64, args ...uint64) (interface{}, error) {
return nil, ErrInvalidArgumentCount
}
compiled := vm.compiledFuncs[fnIndex]
if len(vm.ctx.stack) < compiled.maxDepth {
vm.ctx.stack = make([]uint64, 0, compiled.maxDepth)
}

vm.ctx.stack = make([]uint64, 0, compiled.maxDepth)
vm.ctx.locals = make([]uint64, compiled.totalLocalVars)
vm.ctx.pc = 0
vm.ctx.code = compiled.code
Expand Down
46 changes: 23 additions & 23 deletions wasm/operators/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@ import (
)

var (
I32Load = newOp(0x28, "i32.load", nil, wasm.ValueTypeI32)
I64Load = newOp(0x29, "i64.load", nil, wasm.ValueTypeI64)
F32Load = newOp(0x2a, "f32.load", nil, wasm.ValueTypeF32)
F64Load = newOp(0x2b, "f64.load", nil, wasm.ValueTypeF64)
I32Load8s = newOp(0x2c, "i32.load8_s", nil, wasm.ValueTypeI32)
I32Load8u = newOp(0x2d, "i32.load8_u", nil, wasm.ValueTypeI32)
I32Load16s = newOp(0x2e, "i32.load16_s", nil, wasm.ValueTypeI32)
I32Load16u = newOp(0x2f, "i32.load16_u", nil, wasm.ValueTypeI32)
I64Load8s = newOp(0x30, "i64.load8_s", nil, wasm.ValueTypeI64)
I64Load8u = newOp(0x31, "i64.load8_u", nil, wasm.ValueTypeI64)
I64Load16s = newOp(0x32, "i64.load16_s", nil, wasm.ValueTypeI64)
I64Load16u = newOp(0x33, "i64.load16_u", nil, wasm.ValueTypeI64)
I64Load32s = newOp(0x34, "i64.load32_s", nil, wasm.ValueTypeI64)
I64Load32u = newOp(0x35, "i64.load32_u", nil, wasm.ValueTypeI64)
I32Load = newOp(0x28, "i32.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
I64Load = newOp(0x29, "i64.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
F32Load = newOp(0x2a, "f32.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeF32)
F64Load = newOp(0x2b, "f64.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeF64)
I32Load8s = newOp(0x2c, "i32.load8_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
I32Load8u = newOp(0x2d, "i32.load8_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
I32Load16s = newOp(0x2e, "i32.load16_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
I32Load16u = newOp(0x2f, "i32.load16_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
I64Load8s = newOp(0x30, "i64.load8_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
I64Load8u = newOp(0x31, "i64.load8_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
I64Load16s = newOp(0x32, "i64.load16_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
I64Load16u = newOp(0x33, "i64.load16_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
I64Load32s = newOp(0x34, "i64.load32_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
I64Load32u = newOp(0x35, "i64.load32_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)

I32Store = newOp(0x36, "i32.store", nil, wasm.ValueTypeI32)
I64Store = newOp(0x37, "i64.store", nil, wasm.ValueTypeI64)
F32Store = newOp(0x38, "f32.store", nil, wasm.ValueTypeF32)
F64Store = newOp(0x39, "f64.store", nil, wasm.ValueTypeF64)
I32Store8 = newOp(0x3a, "i32.store8", nil, wasm.ValueTypeI32)
I32Store16 = newOp(0x3b, "i32.store16", nil, wasm.ValueTypeI32)
I64Store8 = newOp(0x3c, "i64.store8", nil, wasm.ValueTypeI64)
I64Store16 = newOp(0x3d, "i64.store16", nil, wasm.ValueTypeI64)
I64Store32 = newOp(0x3e, "i64.store32", nil, wasm.ValueTypeI32)
I32Store = newOp(0x36, "i32.store", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
I64Store = newOp(0x37, "i64.store", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
F32Store = newOp(0x38, "f32.store", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeI32}, noReturn)
F64Store = newOp(0x39, "f64.store", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeI32}, noReturn)
I32Store8 = newOp(0x3a, "i32.store8", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
I32Store16 = newOp(0x3b, "i32.store16", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
I64Store8 = newOp(0x3c, "i64.store8", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
I64Store16 = newOp(0x3d, "i64.store16", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
I64Store32 = newOp(0x3e, "i64.store32", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)

CurrentMemory = newOp(0x3f, "current_memory", nil, wasm.ValueTypeI32)
GrowMemory = newOp(0x40, "grow_memory", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
Expand Down