From b7d7518af8991dd170a2e5c22856c913e25b7ebb Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 18 Dec 2017 23:56:17 +0530 Subject: [PATCH 01/12] disasm: Fix referencing the incorrect function type in call_indirect In Disassemble, the function uses the integer immediate for call_indirect as an index into the global index space, while it should be an index into the Type Section of the module. This causes it to reference an incorrect function, which would cause stack underflows later on. This CL fixes that. Also, fix the select operator decreasing the stack height by 3 instead of 2. (Fixes #49) --- disasm/disasm.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/disasm/disasm.go b/disasm/disasm.go index 66cda640..60f2f5b3 100644 --- a/disasm/disasm.go +++ b/disasm/disasm.go @@ -157,7 +157,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 { @@ -351,10 +351,18 @@ 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 + if op == ops.CallIndirect { + if module.Types == nil { + return nil, errors.New("missing types section") + } + sig = &module.Types.Entries[index] + } else { + sig = module.GetFunction(int(index)).Sig + } top := int(stackDepths.Top()) - top -= len(fn.Sig.ParamTypes) - top += len(fn.Sig.ReturnTypes) + top -= len(sig.ParamTypes) + top += len(sig.ReturnTypes) stackDepths.SetTop(uint64(top)) disas.checkMaxDepth(top) } From 47f6c98450d530838f023c140c5640c9bbe38f59 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 15:00:08 +0530 Subject: [PATCH 02/12] disasm: Replace BlockInfo.PairIndex with finer grained indices. Replace with BlockInfo.PairIndex four indices: * IfElseIndex - For an if instruction, this is the index to the corresponding else instruction. * ElseIfIndex - For an else instruction, this is the index to the corresponding if instruction. * EndIndex - For a block/loop/if/else instruction, this is the index to the corresponding end instruction. * BlockStartIndex - For an end instruction, this is the index to the instruction that started the block itself. --- disasm/disasm.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/disasm/disasm.go b/disasm/disasm.go index 60f2f5b3..f1e82a28 100644 --- a/disasm/disasm.go +++ b/disasm/disasm.go @@ -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. @@ -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, From 04ecfb4db160fb6ac54283bc8c937ce83d9d9730 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 18:41:34 +0530 Subject: [PATCH 03/12] internal/compile: Use the newly added BlockInfo indices. --- exec/internal/compile/compile.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/exec/internal/compile/compile.go b/exec/internal/compile/compile.go index 840957aa..3441cbe3 100644 --- a/exec/internal/compile/compile.go +++ b/exec/internal/compile/compile.go @@ -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()) From d5dcd42b754c195f1907b1e58539808df62e2c69 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 18:42:09 +0530 Subject: [PATCH 04/12] disasm: Decrement the stack depth on encountering call_indirect. --- disasm/disasm.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disasm/disasm.go b/disasm/disasm.go index f1e82a28..6fdd55ab 100644 --- a/disasm/disasm.go +++ b/disasm/disasm.go @@ -362,15 +362,16 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { } if !instr.Unreachable { var sig *wasm.FunctionSig + top := int(stackDepths.Top()) 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 := int(stackDepths.Top()) top -= len(sig.ParamTypes) top += len(sig.ReturnTypes) stackDepths.SetTop(uint64(top)) From 1eec7683b306dbcef6ba5c1211249177577d4ec8 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 18:43:04 +0530 Subject: [PATCH 05/12] exec: Set the new stack's length to zero in doCall. --- exec/call.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec/call.go b/exec/call.go index 65d735f7..7f279c46 100644 --- a/exec/call.go +++ b/exec/call.go @@ -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-- { From f0f7df6d8898ed60a9231a66f1eb0a8c1a4eee46 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 18:44:40 +0530 Subject: [PATCH 06/12] exec: callIndirect: Use the correct index in doCall. --- exec/call.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec/call.go b/exec/call.go index 7f279c46..757e835a 100644 --- a/exec/call.go +++ b/exec/call.go @@ -81,5 +81,5 @@ func (vm *VM) callIndirect() { } } - vm.doCall(vm.compiledFuncs[elemIndex], int64(index)) + vm.doCall(vm.compiledFuncs[elemIndex], int64(elemIndex)) } From 100fa4ebca1b1900fba689f9b9e23d41f7b6092e Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 5 Apr 2018 18:54:38 +0530 Subject: [PATCH 07/12] exec: ExecCode: Don't reuse the stack. This ensures the stack length always starts with 0. --- exec/vm.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exec/vm.go b/exec/vm.go index cb1ba360..3a12c0aa 100644 --- a/exec/vm.go +++ b/exec/vm.go @@ -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 From 71112338708d6f081869818d3ff8bf9b80bea31d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 6 Apr 2018 11:40:10 +0530 Subject: [PATCH 08/12] disasm: Add more debug logging statements. --- disasm/disasm.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/disasm/disasm.go b/disasm/disasm.go index 6fdd55ab..2cc64804 100644 --- a/disasm/disasm.go +++ b/disasm/disasm.go @@ -139,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) @@ -211,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] @@ -457,5 +459,9 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { curIndex++ } + for _, instr := range disas.Code { + logger.Printf("%v %v", instr.Op.Name, instr.NewStack) + } + return disas, nil } From d63726cfdf734ac8b1ace3930d804ab615dfae2d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 6 Apr 2018 11:40:45 +0530 Subject: [PATCH 09/12] wasm/operators: Use correct argument types for memory operators. --- wasm/operators/memory.go | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/wasm/operators/memory.go b/wasm/operators/memory.go index 24c92dbe..9aafa00a 100644 --- a/wasm/operators/memory.go +++ b/wasm/operators/memory.go @@ -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) From 3eae20dc565789de177c0916f95936e9702572d3 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 6 Apr 2018 11:46:27 +0530 Subject: [PATCH 10/12] disasm: Replace PrintDegbugInfo with function SetDebugMode. SetDebugMode allows logging functionality to be enabled or disabled at will. --- disasm/log.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/disasm/log.go b/disasm/log.go index 36478390..cb65a4e6 100644 --- a/disasm/log.go +++ b/disasm/log.go @@ -10,17 +10,20 @@ import ( "os" ) -var PrintDebugInfo = false - var logger *log.Logger -func init() { +func SetDebugMode(l bool) { w := ioutil.Discard - if PrintDebugInfo { + if l { w = os.Stderr } logger = log.New(w, "", log.Lshortfile) logger.SetFlags(log.Lshortfile) + +} + +func init() { + SetDebugMode(false) } From ff65b24607aa84817de079bf1e16a9d696d53599 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 6 Apr 2018 11:54:40 +0530 Subject: [PATCH 11/12] exec_test: Add new test, bug-49. This CL adds the new WebAssembly module from Bug #49. --- exec/testdata/bug-49.wasm | Bin 0 -> 38665 bytes exec/testdata/modules.json | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 exec/testdata/bug-49.wasm diff --git a/exec/testdata/bug-49.wasm b/exec/testdata/bug-49.wasm new file mode 100644 index 0000000000000000000000000000000000000000..fb6eb487c26285571c5c514624cfcb51128eee1d GIT binary patch literal 38665 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 Date: Mon, 9 Apr 2018 19:54:13 +0530 Subject: [PATCH 12/12] disasm: Add private var "logging". --- disasm/disasm.go | 6 ++++-- disasm/log.go | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/disasm/disasm.go b/disasm/disasm.go index 2cc64804..d9f6fc16 100644 --- a/disasm/disasm.go +++ b/disasm/disasm.go @@ -459,8 +459,10 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { curIndex++ } - for _, instr := range disas.Code { - logger.Printf("%v %v", instr.Op.Name, instr.NewStack) + if logging { + for _, instr := range disas.Code { + logger.Printf("%v %v", instr.Op.Name, instr.NewStack) + } } return disas, nil diff --git a/disasm/log.go b/disasm/log.go index cb65a4e6..4b6912cc 100644 --- a/disasm/log.go +++ b/disasm/log.go @@ -10,10 +10,14 @@ import ( "os" ) -var logger *log.Logger +var ( + logger *log.Logger + logging bool +) func SetDebugMode(l bool) { w := ioutil.Discard + logging = l if l { w = os.Stderr