forked from TrueCloudLab/neoneo-go
Merge pull request #427 from nspcc-dev/feat/max_size
Arrays, Structs and Maps have maximum size defined as MaxArraySize. We need to return an error in case collection becomes too big. Part of #373.
This commit is contained in:
commit
19a0d16751
2 changed files with 97 additions and 5 deletions
25
pkg/vm/vm.go
25
pkg/vm/vm.go
|
@ -753,8 +753,11 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) {
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
v.estack.PushVal(t)
|
v.estack.PushVal(t)
|
||||||
default:
|
default:
|
||||||
n := item.BigInt()
|
n := item.BigInt().Int64()
|
||||||
items := makeArrayOfFalses(int(n.Int64()))
|
if n > MaxArraySize {
|
||||||
|
panic("too long array")
|
||||||
|
}
|
||||||
|
items := makeArrayOfFalses(int(n))
|
||||||
v.estack.PushVal(&ArrayItem{items})
|
v.estack.PushVal(&ArrayItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,8 +769,11 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) {
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
v.estack.PushVal(t)
|
v.estack.PushVal(t)
|
||||||
default:
|
default:
|
||||||
n := item.BigInt()
|
n := item.BigInt().Int64()
|
||||||
items := makeArrayOfFalses(int(n.Int64()))
|
if n > MaxArraySize {
|
||||||
|
panic("too long struct")
|
||||||
|
}
|
||||||
|
items := makeArrayOfFalses(int(n))
|
||||||
v.estack.PushVal(&StructItem{items})
|
v.estack.PushVal(&StructItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,10 +786,16 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) {
|
||||||
switch t := arrElem.value.(type) {
|
switch t := arrElem.value.(type) {
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
arr := t.Value().([]StackItem)
|
arr := t.Value().([]StackItem)
|
||||||
|
if len(arr) >= MaxArraySize {
|
||||||
|
panic("too long array")
|
||||||
|
}
|
||||||
arr = append(arr, val)
|
arr = append(arr, val)
|
||||||
t.value = arr
|
t.value = arr
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
arr := t.Value().([]StackItem)
|
arr := t.Value().([]StackItem)
|
||||||
|
if len(arr) >= MaxArraySize {
|
||||||
|
panic("too long struct")
|
||||||
|
}
|
||||||
arr = append(arr, val)
|
arr = append(arr, val)
|
||||||
t.value = arr
|
t.value = arr
|
||||||
default:
|
default:
|
||||||
|
@ -792,7 +804,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) {
|
||||||
|
|
||||||
case PACK:
|
case PACK:
|
||||||
n := int(v.estack.Pop().BigInt().Int64())
|
n := int(v.estack.Pop().BigInt().Int64())
|
||||||
if n < 0 || n > v.estack.Len() {
|
if n < 0 || n > v.estack.Len() || n > MaxArraySize {
|
||||||
panic("OPACK: invalid length")
|
panic("OPACK: invalid length")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,6 +871,9 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) {
|
||||||
}
|
}
|
||||||
arr[index] = item
|
arr[index] = item
|
||||||
case *MapItem:
|
case *MapItem:
|
||||||
|
if !t.Has(key.value) && len(t.value) >= MaxArraySize {
|
||||||
|
panic("too big map")
|
||||||
|
}
|
||||||
t.Add(key.value, item)
|
t.Add(key.value, item)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -538,6 +538,14 @@ func TestNEWARRAYByteArray(t *testing.T) {
|
||||||
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
|
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNEWARRAYBadSize(t *testing.T) {
|
||||||
|
prog := makeProgram(NEWARRAY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(MaxArraySize + 1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
func TestNEWSTRUCTInteger(t *testing.T) {
|
func TestNEWSTRUCTInteger(t *testing.T) {
|
||||||
prog := makeProgram(NEWSTRUCT)
|
prog := makeProgram(NEWSTRUCT)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -580,6 +588,14 @@ func TestNEWSTRUCTByteArray(t *testing.T) {
|
||||||
assert.Equal(t, &StructItem{[]StackItem{}}, vm.estack.Pop().value)
|
assert.Equal(t, &StructItem{[]StackItem{}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNEWSTRUCTBadSize(t *testing.T) {
|
||||||
|
prog := makeProgram(NEWSTRUCT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(MaxArraySize + 1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPPENDArray(t *testing.T) {
|
func TestAPPENDArray(t *testing.T) {
|
||||||
prog := makeProgram(DUP, PUSH5, APPEND)
|
prog := makeProgram(DUP, PUSH5, APPEND)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -636,6 +652,24 @@ func TestAPPENDWrongType(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.HasFailed())
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPPENDGoodSizeLimit(t *testing.T) {
|
||||||
|
prog := makeProgram(NEWARRAY, DUP, PUSH0, APPEND)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(MaxArraySize - 1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, MaxArraySize, len(vm.estack.Pop().Array()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPPENDBadSizeLimit(t *testing.T) {
|
||||||
|
prog := makeProgram(NEWARRAY, DUP, PUSH0, APPEND)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(MaxArraySize)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
func TestPICKITEMBadIndex(t *testing.T) {
|
func TestPICKITEMBadIndex(t *testing.T) {
|
||||||
prog := makeProgram(PICKITEM)
|
prog := makeProgram(PICKITEM)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -700,6 +734,38 @@ func TestSETITEMMap(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSETITEMBigMapBad(t *testing.T) {
|
||||||
|
prog := makeProgram(SETITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
for i := 0; i < MaxArraySize; i++ {
|
||||||
|
m.Add(makeStackItem(i), makeStackItem(i))
|
||||||
|
}
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(MaxArraySize)
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSETITEMBigMapGood(t *testing.T) {
|
||||||
|
prog := makeProgram(SETITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
for i := 0; i < MaxArraySize; i++ {
|
||||||
|
m.Add(makeStackItem(i), makeStackItem(i))
|
||||||
|
}
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
func TestSIZENoArgument(t *testing.T) {
|
func TestSIZENoArgument(t *testing.T) {
|
||||||
prog := makeProgram(SIZE)
|
prog := makeProgram(SIZE)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -1570,6 +1636,17 @@ func TestPACKBadLen(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.HasFailed())
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPACKBigLen(t *testing.T) {
|
||||||
|
prog := makeProgram(PACK)
|
||||||
|
vm := load(prog)
|
||||||
|
for i := 0; i <= MaxArraySize; i++ {
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
}
|
||||||
|
vm.estack.PushVal(MaxArraySize + 1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
func TestPACKGoodZeroLen(t *testing.T) {
|
func TestPACKGoodZeroLen(t *testing.T) {
|
||||||
prog := makeProgram(PACK)
|
prog := makeProgram(PACK)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue