From f2f66ad36e1d00bd3702b5bf096570e7e27ddb70 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 17 May 2022 14:41:07 +0300 Subject: [PATCH 1/2] vm: clear static slot refs on exit, fix #2501 --- pkg/vm/vm.go | 2 +- pkg/vm/vm_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 801d68846..44f905cbb 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1588,7 +1588,7 @@ func (v *VM) unloadContext(ctx *Context) { ctx.arguments.ClearRefs(&v.refs) } currCtx := v.Context() - if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static { + if ctx.static != nil && (currCtx == nil || ctx.static != currCtx.static) { ctx.static.ClearRefs(&v.refs) } } diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 0e88a14e4..e3bd59256 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -2718,6 +2718,35 @@ func TestNestedStructEquals(t *testing.T) { checkVMFailed(t, vm) } +func TestRemoveReferrer(t *testing.T) { + h := "560110c34a10c36058cf4540" // #2501 + prog, err := hex.DecodeString(h) + require.NoError(t, err) + vm := load(prog) + require.NoError(t, vm.StepInto()) // INITSSLOT + assert.Equal(t, 1, int(vm.refs)) + require.NoError(t, vm.StepInto()) // PUSH0 + assert.Equal(t, 2, int(vm.refs)) + require.NoError(t, vm.StepInto()) // NEWARRAY + assert.Equal(t, 2, int(vm.refs)) + require.NoError(t, vm.StepInto()) // DUP + assert.Equal(t, 3, int(vm.refs)) + require.NoError(t, vm.StepInto()) // PUSH0 + assert.Equal(t, 4, int(vm.refs)) + require.NoError(t, vm.StepInto()) // NEWARRAY + assert.Equal(t, 4, int(vm.refs)) + require.NoError(t, vm.StepInto()) // STSFLD0 + assert.Equal(t, 3, int(vm.refs)) + require.NoError(t, vm.StepInto()) // LDSFLD0 + assert.Equal(t, 4, int(vm.refs)) + require.NoError(t, vm.StepInto()) // APPEND + assert.Equal(t, 3, int(vm.refs)) + require.NoError(t, vm.StepInto()) // DROP + assert.Equal(t, 1, int(vm.refs)) + require.NoError(t, vm.StepInto()) // RET + assert.Equal(t, 0, int(vm.refs)) +} + func makeProgram(opcodes ...opcode.Opcode) []byte { prog := make([]byte, len(opcodes)+1) // RET for i := 0; i < len(opcodes); i++ { From ae2395f55fccdef5ecee781b3be095fc6a0dca01 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 17 May 2022 14:45:08 +0300 Subject: [PATCH 2/2] vm: simplify (slot).Set code Refcounter handles nil items just fine. --- pkg/vm/slot.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/vm/slot.go b/pkg/vm/slot.go index 4544ab8dd..661e796d8 100644 --- a/pkg/vm/slot.go +++ b/pkg/vm/slot.go @@ -23,13 +23,8 @@ func (s slot) Set(i int, item stackitem.Item, refs *refCounter) { if s[i] == item { return } - old := s[i] + refs.Remove(s[i]) s[i] = item - if old != nil { - refs.Remove(old) - } else { - *refs-- // Not really existing, but counted Null element. - } refs.Add(item) }