From 46b8efca9a18986815e5a3d895b5d47450d2971e Mon Sep 17 00:00:00 2001 From: radik878 Date: Sat, 24 Jan 2026 00:31:32 +0200 Subject: [PATCH 1/3] fix: correct off-by-one in ArrayPoolListCore.RemoveAt --- src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs index e801a3f3fa9..87a49232c52 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs @@ -192,7 +192,7 @@ public static bool RemoveAt(T[] array, ref int count, int index, bool shouldThro int start = index + 1; if (start < count) { - array.AsMemory(start, count - index).CopyTo(array.AsMemory(index)); + array.AsMemory(start, count - index - 1).CopyTo(array.AsMemory(index)); } count--; From 8f6bccdd9104fa1ecc12f31892d8ecdb4b094b8b Mon Sep 17 00:00:00 2001 From: radik878 Date: Sat, 24 Jan 2026 00:32:54 +0200 Subject: [PATCH 2/3] add test --- .../Collections/ArrayPoolListTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs index 296a58c9893..dc8faa920b4 100644 --- a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -336,6 +337,32 @@ public void Dispose_recursive() list.DisposeRecursive(); } + [Test] + public void RemoveAt_should_not_throw_when_capacity_equals_count() + { + ArrayPool pool = new ExactSizeArrayPool(); + using ArrayPoolList list = new(pool, 8, 8); + + for (int i = 0; i < list.Count; i++) + { + list[i] = i; + } + + Action act = () => list.RemoveAt(2); + + act.Should().NotThrow(); + list.Should().BeEquivalentTo(new[] { 0, 1, 3, 4, 5, 6, 7 }); + } + + private sealed class ExactSizeArrayPool : ArrayPool + { + public override T[] Rent(int minimumLength) => new T[minimumLength]; + + public override void Return(T[] array, bool clearArray = false) + { + } + } + #if DEBUG [Test] [Explicit("Crashes the test runner")] From 4c95566ff397dc22634bbe1fd6d4dfb60c4208ab Mon Sep 17 00:00:00 2001 From: radik878 Date: Sun, 25 Jan 2026 14:26:34 +0200 Subject: [PATCH 3/3] Update src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs Co-authored-by: Lukasz Rozmej --- src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs index 87a49232c52..00b95e68395 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayListCore.cs @@ -192,7 +192,7 @@ public static bool RemoveAt(T[] array, ref int count, int index, bool shouldThro int start = index + 1; if (start < count) { - array.AsMemory(start, count - index - 1).CopyTo(array.AsMemory(index)); + array.AsMemory(start, count - start).CopyTo(array.AsMemory(index)); } count--;