From 0d93b353e6213daf58a501696fba5ce63dae439a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 May 2022 17:42:57 +0300 Subject: [PATCH] vm: count initial Null slot variables as well Match C# behavior. Thanks to @ixje for finding this. --- pkg/vm/opcodebench_test.go | 6 +++--- pkg/vm/slot.go | 9 ++++++--- pkg/vm/slot_test.go | 4 +++- pkg/vm/vm.go | 12 ++++++------ pkg/vm/vm_test.go | 4 ++-- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/pkg/vm/opcodebench_test.go b/pkg/vm/opcodebench_test.go index 465a9943e..0c68ae647 100644 --- a/pkg/vm/opcodebench_test.go +++ b/pkg/vm/opcodebench_test.go @@ -56,11 +56,11 @@ func opParamSlotsPushVM(op opcode.Opcode, param []byte, sslot int, slotloc int, return nil } if sslot != 0 { - v.Context().static.init(sslot) + v.Context().static.init(sslot, &v.refs) } if slotloc != 0 && slotarg != 0 { - v.Context().local.init(slotloc) - v.Context().arguments.init(slotarg) + v.Context().local.init(slotloc, &v.refs) + v.Context().arguments.init(slotarg, &v.refs) } for i := range items { item, ok := items[i].(stackitem.Item) diff --git a/pkg/vm/slot.go b/pkg/vm/slot.go index 69645f689..4544ab8dd 100644 --- a/pkg/vm/slot.go +++ b/pkg/vm/slot.go @@ -10,11 +10,12 @@ import ( type slot []stackitem.Item // init sets static slot size to n. It is intended to be used only by INITSSLOT. -func (s *slot) init(n int) { +func (s *slot) init(n int, rc *refCounter) { if *s != nil { panic("already initialized") } *s = make([]stackitem.Item, n) + *rc += refCounter(n) // Virtual "Null" elements. } // Set sets i-th storage slot. @@ -26,6 +27,8 @@ func (s slot) Set(i int, item stackitem.Item, refs *refCounter) { s[i] = item if old != nil { refs.Remove(old) + } else { + *refs-- // Not really existing, but counted Null element. } refs.Add(item) } @@ -38,8 +41,8 @@ func (s slot) Get(i int) stackitem.Item { return stackitem.Null{} } -// Clear removes all slot variables from the reference counter. -func (s slot) Clear(refs *refCounter) { +// ClearRefs removes all slot variables from the reference counter. +func (s slot) ClearRefs(refs *refCounter) { for _, item := range s { refs.Remove(item) } diff --git a/pkg/vm/slot_test.go b/pkg/vm/slot_test.go index 212470a9f..ec10a7ffc 100644 --- a/pkg/vm/slot_test.go +++ b/pkg/vm/slot_test.go @@ -13,8 +13,9 @@ func TestSlot_Get(t *testing.T) { var s slot require.Panics(t, func() { s.Size() }) - s.init(3) + s.init(3, rc) require.Equal(t, 3, s.Size()) + require.Equal(t, 3, int(*rc)) // Null is the default item := s.Get(2) @@ -22,4 +23,5 @@ func TestSlot_Get(t *testing.T) { s.Set(1, stackitem.NewBigInteger(big.NewInt(42)), rc) require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1)) + require.Equal(t, 3, int(*rc)) } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index cc446ee4d..801d68846 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -616,7 +616,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro if parameter[0] == 0 { panic("zero argument") } - ctx.static.init(int(parameter[0])) + ctx.static.init(int(parameter[0]), &v.refs) case opcode.INITSLOT: if ctx.local != nil || ctx.arguments != nil { @@ -626,11 +626,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro panic("zero argument") } if parameter[0] > 0 { - ctx.local.init(int(parameter[0])) + ctx.local.init(int(parameter[0]), &v.refs) } if parameter[1] > 0 { sz := int(parameter[1]) - ctx.arguments.init(sz) + ctx.arguments.init(sz, &v.refs) for i := 0; i < sz; i++ { ctx.arguments.Set(i, v.estack.Pop().Item(), &v.refs) } @@ -1582,14 +1582,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro func (v *VM) unloadContext(ctx *Context) { if ctx.local != nil { - ctx.local.Clear(&v.refs) + ctx.local.ClearRefs(&v.refs) } if ctx.arguments != nil { - ctx.arguments.Clear(&v.refs) + ctx.arguments.ClearRefs(&v.refs) } currCtx := v.Context() if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static { - ctx.static.Clear(&v.refs) + ctx.static.ClearRefs(&v.refs) } } diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 179fbd8c1..0e88a14e4 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -387,8 +387,8 @@ func TestStackLimit(t *testing.T) { inst opcode.Opcode size int }{ - {opcode.PUSH2, 1}, - {opcode.NEWARRAY, 3}, // array + 2 items + {opcode.PUSH2, 2}, // 1 from INITSSLOT and 1 for integer 2 + {opcode.NEWARRAY, 4}, // array + 2 items {opcode.STSFLD0, 3}, {opcode.LDSFLD0, 4}, {opcode.NEWMAP, 5},