From 063c29636b53d9b980588819678f442b9303422a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 20 May 2020 17:09:57 +0300 Subject: [PATCH] vm: fail if NEWSTRUCT/NEWARRAY argument is not an integer NEO3 VM does not support creating new Array from a Struct. For this purpose CONVERT opcode is used. --- pkg/vm/vm.go | 46 ++++++++++++++-------------------------------- pkg/vm/vm_test.go | 37 ++++++++++++++----------------------- 2 files changed, 28 insertions(+), 55 deletions(-) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index f05a8259a..ad4c4ebec 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -981,46 +981,28 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.NEWARRAY, opcode.NEWARRAYT: item := v.estack.Pop() - switch t := item.value.(type) { - case *StructItem: - arr := make([]StackItem, len(t.value)) - copy(arr, t.value) - v.estack.PushVal(&ArrayItem{arr}) - case *ArrayItem: - v.estack.PushVal(t) - default: - n := item.BigInt().Int64() - if n > MaxArraySize { - panic("too long array") - } - typ := AnyT - if op == opcode.NEWARRAYT { - typ = StackItemType(parameter[0]) - } - items := makeArrayOfType(int(n), typ) - v.estack.PushVal(&ArrayItem{items}) + n := item.BigInt().Int64() + if n > MaxArraySize { + panic("too long array") } + typ := AnyT + if op == opcode.NEWARRAYT { + typ = StackItemType(parameter[0]) + } + items := makeArrayOfType(int(n), typ) + v.estack.PushVal(&ArrayItem{items}) case opcode.NEWSTRUCT0: v.estack.PushVal(&StructItem{[]StackItem{}}) case opcode.NEWSTRUCT: item := v.estack.Pop() - switch t := item.value.(type) { - case *ArrayItem: - arr := make([]StackItem, len(t.value)) - copy(arr, t.value) - v.estack.PushVal(&StructItem{arr}) - case *StructItem: - v.estack.PushVal(t) - default: - n := item.BigInt().Int64() - if n > MaxArraySize { - panic("too long struct") - } - items := makeArrayOfType(int(n), AnyT) - v.estack.PushVal(&StructItem{items}) + n := item.BigInt().Int64() + if n > MaxArraySize { + panic("too long struct") } + items := makeArrayOfType(int(n), AnyT) + v.estack.PushVal(&StructItem{items}) case opcode.APPEND: itemElem := v.estack.Pop() diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 3166e4c11..dcb949e54 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -372,7 +372,7 @@ func appendBigStruct(size uint16) []opcode.Opcode { return append(prog, opcode.INITSSLOT, 1, opcode.PUSHINT16, opcode.Opcode(size), opcode.Opcode(size>>8), // LE - opcode.PACK, opcode.NEWSTRUCT, + opcode.PACK, opcode.CONVERT, opcode.Opcode(StructT), opcode.STSFLD0, opcode.LDSFLD0, opcode.DUP, opcode.PUSH0, opcode.NEWARRAY, @@ -401,20 +401,19 @@ func TestStackLimit(t *testing.T) { {opcode.NEWARRAY, 3}, // array + 2 items {opcode.STSFLD0, 3}, {opcode.LDSFLD0, 4}, - {opcode.NEWSTRUCT, 6}, // all items are copied - {opcode.NEWMAP, 7}, - {opcode.DUP, 8}, - {opcode.PUSH2, 9}, - {opcode.LDSFLD0, 10}, - {opcode.SETITEM, 8}, // -3 items and 1 new element in map - {opcode.DUP, 9}, - {opcode.PUSH2, 10}, - {opcode.LDSFLD0, 11}, - {opcode.SETITEM, 8}, // -3 items and no new elements in map - {opcode.DUP, 9}, - {opcode.PUSH2, 10}, - {opcode.REMOVE, 7}, // as we have right after NEWMAP - {opcode.DROP, 6}, // DROP map with no elements + {opcode.NEWMAP, 5}, + {opcode.DUP, 6}, + {opcode.PUSH2, 7}, + {opcode.LDSFLD0, 8}, + {opcode.SETITEM, 6}, // -3 items and 1 new element in map + {opcode.DUP, 7}, + {opcode.PUSH2, 8}, + {opcode.LDSFLD0, 9}, + {opcode.SETITEM, 6}, // -3 items and no new elements in map + {opcode.DUP, 7}, + {opcode.PUSH2, 8}, + {opcode.REMOVE, 5}, // as we have right after NEWMAP + {opcode.DROP, 4}, // DROP map with no elements } prog := make([]opcode.Opcode, len(expected)+2) @@ -1189,10 +1188,6 @@ func TestNEWARRAYArray(t *testing.T) { t.Run("ByteArray", getTestFuncForVM(prog, NewArrayItem([]StackItem{}), []byte{})) t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) t.Run("Integer", getTestFuncForVM(prog, []StackItem{NullItem{}}, 1)) - - arr := []StackItem{makeStackItem(42)} - t.Run("Array", getTestFuncForVM(prog, arr, arr)) - t.Run("Struct", getTestFuncForVM(prog, arr, NewStructItem(arr))) } func testNEWARRAYIssue437(t *testing.T, i1 opcode.Opcode, t2 StackItemType, appended bool) { @@ -1244,10 +1239,6 @@ func TestNEWSTRUCT(t *testing.T) { t.Run("ByteArray", getTestFuncForVM(prog, NewStructItem([]StackItem{}), []byte{})) t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NullItem{}}), 1)) - - arr := []StackItem{makeStackItem(42)} - t.Run("Array", getTestFuncForVM(prog, NewStructItem(arr), NewArrayItem(arr))) - t.Run("Struct", getTestFuncForVM(prog, NewStructItem(arr), NewStructItem(arr))) } func TestAPPEND(t *testing.T) {