From c66df889c3cbcc704e27748b8a937aac302707ee Mon Sep 17 00:00:00 2001 From: Wi1l-B0t <201105916+Wi1l-B0t@users.noreply.github.com> Date: Fri, 27 Jun 2025 09:21:49 +0800 Subject: [PATCH 1/2] Fix: wrong reference count after invalid Map[key] = value --- src/Neo.VM/Types/Map.cs | 8 ++++---- tests/Neo.VM.Tests/UT_ReferenceCounter.cs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs index bdc299ba56..545da6a20f 100644 --- a/src/Neo.VM/Types/Map.cs +++ b/src/Neo.VM/Types/Map.cs @@ -51,14 +51,14 @@ public StackItem this[PrimitiveType key] if (IsReadOnly) throw new InvalidOperationException("The map is readonly, can not set value."); if (ReferenceCounter != null) { + if (value is CompoundType { ReferenceCounter: null }) + throw new InvalidOperationException("Can not set value to Map(with ReferenceCounter) without ReferenceCounter."); + if (dictionary.TryGetValue(key, out StackItem? old_value)) ReferenceCounter.RemoveReference(old_value, this); else ReferenceCounter.AddReference(key, this); - if (value is CompoundType { ReferenceCounter: null }) - { - throw new InvalidOperationException("Can not set a Map without a ReferenceCounter."); - } + ReferenceCounter.AddReference(value, this); } dictionary[key] = value; diff --git a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs index 9c450bd7ae..519f0ebd80 100644 --- a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs @@ -257,5 +257,22 @@ public void TestInvalidReferenceStackItem() Assert.ThrowsExactly(() => arr.Add(arr2)); } + + [TestMethod] + public void TestInvalidMapSet() + { + var reference = new ReferenceCounter(); + var map = new Map(reference); + Assert.AreEqual(0, reference.Count); // map is zero-referred + + map["test"] = new Array(reference); + Assert.AreEqual(2, reference.Count); // one key + one value + + Assert.ThrowsExactly(() => map["test"] = new Array()); + Assert.AreEqual(2, reference.Count); // not changed after invalid set + + map["test"] = new Integer(1); // overwrite the value + Assert.AreEqual(2, reference.Count); // not changed after overwrite + } } } From 0333166dd3b594545cd814614e9410868c4eeb75 Mon Sep 17 00:00:00 2001 From: Wi1l-B0t <201105916+Wi1l-B0t@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:44:42 +0800 Subject: [PATCH 2/2] Fix: wrong reference count in Array ctor --- src/Neo.VM/Types/Array.cs | 5 ++-- tests/Neo.VM.Tests/UT_ReferenceCounter.cs | 32 ++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Neo.VM/Types/Array.cs b/src/Neo.VM/Types/Array.cs index a44454d3f3..f30367a03f 100644 --- a/src/Neo.VM/Types/Array.cs +++ b/src/Neo.VM/Types/Array.cs @@ -83,10 +83,11 @@ public Array(IReferenceCounter? referenceCounter, IEnumerable? items foreach (var item in _array) { if (item is CompoundType { ReferenceCounter: null }) - { throw new InvalidOperationException("Can not set a CompoundType without a ReferenceCounter."); - } + } + foreach (var item in _array) + { referenceCounter.AddReference(item, this); } } diff --git a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs index 519f0ebd80..fbc82aa4bd 100644 --- a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs @@ -261,18 +261,32 @@ public void TestInvalidReferenceStackItem() [TestMethod] public void TestInvalidMapSet() { - var reference = new ReferenceCounter(); - var map = new Map(reference); - Assert.AreEqual(0, reference.Count); // map is zero-referred + { + var reference = new ReferenceCounter(); + var map = new Map(reference); + Assert.AreEqual(0, reference.Count); // map is zero-referred + + map["test"] = new Array(reference); + Assert.AreEqual(2, reference.Count); // one key + one value + + Assert.ThrowsExactly(() => map["test"] = new Array()); + Assert.AreEqual(2, reference.Count); // not changed after invalid set + + map["test"] = new Integer(1); // overwrite the value + Assert.AreEqual(2, reference.Count); // not changed after overwrite + } - map["test"] = new Array(reference); - Assert.AreEqual(2, reference.Count); // one key + one value - Assert.ThrowsExactly(() => map["test"] = new Array()); - Assert.AreEqual(2, reference.Count); // not changed after invalid set + { + var reference = new ReferenceCounter(); + var map = new Map(); + Assert.ThrowsExactly(() => new Array(reference, [map])); - map["test"] = new Integer(1); // overwrite the value - Assert.AreEqual(2, reference.Count); // not changed after overwrite + map = new Map(reference); + var array = new Array(reference, [map]); + Assert.AreEqual(1, reference.Count); + Assert.AreEqual(1, array.Count); + } } } }