From 39866b85125f3891d031e49a329af08d802fc322 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 9 Mar 2022 17:34:36 +0300 Subject: [PATCH] vm: fix integer conversions As can be seen in https://dotnetfiddle.net/s7eg21 (int) conversions result in an exception in C# code. Signed-off-by: Evgeniy Stratonikov --- pkg/vm/vm.go | 30 +++++++++++++++--------------- pkg/vm/vm_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 738600b8e..006511f31 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -723,11 +723,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro v.estack.PushItem(stackitem.NewBuffer(ab)) case opcode.SUBSTR: - l := int(v.estack.Pop().BigInt().Int64()) + l := toInt(v.estack.Pop().BigInt()) if l < 0 { panic("negative length") } - o := int(v.estack.Pop().BigInt().Int64()) + o := toInt(v.estack.Pop().BigInt()) if o < 0 { panic("negative index") } @@ -741,7 +741,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro v.estack.PushItem(stackitem.NewBuffer(res)) case opcode.LEFT: - l := int(v.estack.Pop().BigInt().Int64()) + l := toInt(v.estack.Pop().BigInt()) if l < 0 { panic("negative length") } @@ -754,7 +754,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro v.estack.PushItem(stackitem.NewBuffer(res)) case opcode.RIGHT: - l := int(v.estack.Pop().BigInt().Int64()) + l := toInt(v.estack.Pop().BigInt()) if l < 0 { panic("negative length") } @@ -779,7 +779,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro _ = v.estack.RemoveAt(1) case opcode.XDROP: - n := int(v.estack.Pop().BigInt().Int64()) + n := toInt(v.estack.Pop().BigInt()) if n < 0 { panic("invalid length") } @@ -802,7 +802,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro v.estack.Push(a) case opcode.PICK: - n := int(v.estack.Pop().BigInt().Int64()) + n := toInt(v.estack.Pop().BigInt()) if n < 0 { panic("negative stack item returned") } @@ -832,7 +832,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } case opcode.ROLL: - n := int(v.estack.Pop().BigInt().Int64()) + n := toInt(v.estack.Pop().BigInt()) err := v.estack.Roll(n) if err != nil { panic(err.Error()) @@ -844,7 +844,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.REVERSE4: n = 4 case opcode.REVERSEN: - n = int(v.estack.Pop().BigInt().Int64()) + n = toInt(v.estack.Pop().BigInt()) } if err := v.estack.ReverseTop(n); err != nil { panic(err.Error()) @@ -952,7 +952,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro v.estack.PushItem(stackitem.NewBigInteger(new(big.Int).Sqrt(a))) case opcode.SHL, opcode.SHR: - b := v.estack.Pop().BigInt().Int64() + b := toInt(v.estack.Pop().BigInt()) if b == 0 { return } else if b < 0 || b > maxSHLArg { @@ -1252,7 +1252,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro switch t := elem.value.(type) { case *stackitem.Array: a := t.Value().([]stackitem.Item) - k := int(key.BigInt().Int64()) + k := toInt(key.BigInt()) if k < 0 || k >= len(a) { panic("REMOVE: invalid index") } @@ -1260,7 +1260,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro t.Remove(k) case *stackitem.Struct: a := t.Value().([]stackitem.Item) - k := int(key.BigInt().Int64()) + k := toInt(key.BigInt()) if k < 0 || k >= len(a) { panic("REMOVE: invalid index") } @@ -1454,19 +1454,19 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro var res bool switch t := c.value.(type) { case *stackitem.Array, *stackitem.Struct: - index := key.BigInt().Int64() + index := toInt(key.BigInt()) if index < 0 { panic("negative index") } - res = index < int64(len(c.Array())) + res = index < len(c.Array()) case *stackitem.Map: res = t.Has(key.Item()) case *stackitem.Buffer: - index := key.BigInt().Int64() + index := toInt(key.BigInt()) if index < 0 { panic("negative index") } - res = index < int64(t.Len()) + res = index < t.Len() default: panic("wrong collection type") } diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 6d28db7cf..af82328f9 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -737,6 +737,7 @@ func TestSHR(t *testing.T) { t.Run("Good", getTestFuncForVM(prog, 1, 4, 2)) t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0)) t.Run("Negative", getTestFuncForVM(prog, nil, 5, -1)) + t.Run("very big", getTestFuncForVM(prog, nil, 5, maxu64Plus(1))) } func TestSHL(t *testing.T) { @@ -745,6 +746,7 @@ func TestSHL(t *testing.T) { t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0)) t.Run("BigShift", getTestFuncForVM(prog, nil, 5, maxSHLArg+1)) t.Run("BigResult", getTestFuncForVM(prog, nil, getBigInt(stackitem.MaxBigIntegerSizeBits/2, 0), stackitem.MaxBigIntegerSizeBits/2)) + t.Run("very big shift", getTestFuncForVM(prog, nil, 5, maxu64Plus(1))) } func TestArithNullArg(t *testing.T) { @@ -1418,15 +1420,18 @@ func TestHASKEY(t *testing.T) { arr := makeArrayOfType(5, stackitem.BooleanT) t.Run("Array", func(t *testing.T) { t.Run("True", getTestFuncForVM(prog, true, stackitem.NewArray(arr), 4)) + t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewArray(arr), maxu64Plus(4))) t.Run("False", getTestFuncForVM(prog, false, stackitem.NewArray(arr), 5)) }) t.Run("Struct", func(t *testing.T) { t.Run("True", getTestFuncForVM(prog, true, stackitem.NewStruct(arr), 4)) + t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewStruct(arr), maxu64Plus(4))) t.Run("False", getTestFuncForVM(prog, false, stackitem.NewStruct(arr), 5)) }) t.Run("Buffer", func(t *testing.T) { t.Run("True", getTestFuncForVM(prog, true, stackitem.NewBuffer([]byte{5, 5, 5}), 2)) + t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{5, 5, 5}), maxu64Plus(2))) t.Run("False", getTestFuncForVM(prog, false, stackitem.NewBuffer([]byte{5, 5, 5}), 3)) t.Run("Negative", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{5, 5, 5}), -1)) }) @@ -1497,6 +1502,7 @@ func TestPICK(t *testing.T) { prog := makeProgram(opcode.PICK) t.Run("NoItem", getTestFuncForVM(prog, nil, 1)) t.Run("Negative", getTestFuncForVM(prog, nil, -1)) + t.Run("very big", getTestFuncForVM(prog, nil, 1, 2, 3, maxu64Plus(1))) } func TestPICKgood(t *testing.T) { @@ -1557,6 +1563,17 @@ func TestROLLBad2(t *testing.T) { runWithArgs(t, prog, nil, 1, 2, 3, 3) } +func maxu64Plus(x int64) *big.Int { + bi := new(big.Int).SetUint64(math.MaxUint64) + bi.Add(bi, big.NewInt(2)) + return bi +} + +func TestROLLBad3(t *testing.T) { + prog := makeProgram(opcode.ROLL) + runWithArgs(t, prog, nil, 1, 2, 3, maxu64Plus(2)) +} + func TestROLLGood(t *testing.T) { prog := makeProgram(opcode.ROLL) vm := load(prog) @@ -1602,6 +1619,7 @@ func TestREVERSEN(t *testing.T) { t.Run("Zero", getCustomTestFuncForVM(prog, getCheckEStackFunc(3, 2, 1), 1, 2, 3, 0)) t.Run("OneItem", getCustomTestFuncForVM(prog, getCheckEStackFunc(42), 42, 1)) t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4, 5), 1, 2, 3, 4, 5, 5)) + t.Run("VeryBigNumber", getCustomTestFuncForVM(prog, nil, 1, 2, maxu64Plus(2))) } func TestTUCKbadNoitems(t *testing.T) { @@ -1695,6 +1713,7 @@ func TestXDROP(t *testing.T) { prog := makeProgram(opcode.XDROP) t.Run("NoArgument", getTestFuncForVM(prog, nil)) t.Run("NoN", getTestFuncForVM(prog, nil, 1, 2)) + t.Run("very big argument", getTestFuncForVM(prog, nil, 1, 2, maxu64Plus(1))) t.Run("Negative", getTestFuncForVM(prog, nil, 1, -1)) } @@ -1780,7 +1799,9 @@ func TestSUBSTR(t *testing.T) { t.Run("TwoArguments", getTestFuncForVM(prog, nil, 0, 2)) t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("bc")), []byte("abcdef"), 1, 2)) t.Run("BadOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), 7, 1)) + t.Run("very big offset", getTestFuncForVM(prog, nil, []byte("abcdef"), maxu64Plus(1), 1)) t.Run("BigLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 1, 6)) + t.Run("very big len", getTestFuncForVM(prog, nil, []byte("abcdef"), 1, maxu64Plus(1))) t.Run("NegativeOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), -1, 3)) t.Run("NegativeLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 3, -1)) } @@ -1803,6 +1824,7 @@ func TestLEFT(t *testing.T) { t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1)) t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("ab")), "abcdef", 2)) t.Run("BadBigLen", getTestFuncForVM(prog, nil, "abcdef", 8)) + t.Run("bad, very big len", getTestFuncForVM(prog, nil, "abcdef", maxu64Plus(2))) } func TestRIGHT(t *testing.T) { @@ -1812,6 +1834,7 @@ func TestRIGHT(t *testing.T) { t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1)) t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("ef")), "abcdef", 2)) t.Run("BadLen", getTestFuncForVM(prog, nil, "abcdef", 8)) + t.Run("bad, very big len", getTestFuncForVM(prog, nil, "abcdef", maxu64Plus(2))) } func TestPACK(t *testing.T) { @@ -2059,6 +2082,7 @@ func TestREMOVE(t *testing.T) { t.Run("OneArgument", getTestFuncForVM(prog, nil, 1)) t.Run("NotArray", getTestFuncForVM(prog, nil, 1, 1)) t.Run("BadIndex", getTestFuncForVM(prog, nil, []int{22, 34, 42, 55, 81}, 10)) + t.Run("very big index", getTestFuncForVM(prog, nil, []int{22, 34, 42, 55, 81}, maxu64Plus(1))) } func TestREMOVEGood(t *testing.T) {