From 71e8130def307017bf7255cc508d91853efbe416 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 16:25:57 +0000 Subject: [PATCH] fix: stop RingBuffer.Resample's index mapping overflowing for large buffers [patch] The source index was computed as i * (oldCount - 1) in int before the double division, so once (length - 1) * (oldCount - 1) passed int.MaxValue the product wrapped negative and oldData[index] threw, after AllocateBuffer had already discarded the buffer's contents. Multiply in double instead. Fixes #73 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YXTjHR3MfJpmxt8LEwNkjm --- Containers.Test/RingBufferTests.cs | 23 +++++++++++++++++++++++ Containers/RingBuffer.cs | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Containers.Test/RingBufferTests.cs b/Containers.Test/RingBufferTests.cs index 569cb26..ca644dd 100644 --- a/Containers.Test/RingBufferTests.cs +++ b/Containers.Test/RingBufferTests.cs @@ -290,6 +290,29 @@ public void Resize_NonPositiveLength_Throws() Assert.ThrowsExactly(() => buffer.Resize(-1)); } + [TestMethod] + public void Resample_LargeBufferToSameLength_KeepsContents() + { + const int length = 50_000; + RingBuffer buffer = new(Enumerable.Range(0, length), length); + + buffer.Resample(length); + + Assert.AreSequenceEqual(Enumerable.Range(0, length), buffer); + } + + [TestMethod] + public void Resample_UpsampleToMillionsOfElements_Succeeds() + { + RingBuffer buffer = new(Enumerable.Range(0, 1000), 1000); + + buffer.Resample(3_000_000); + + Assert.HasCount(3_000_000, buffer); + Assert.AreEqual(0, buffer.Front()); + Assert.AreEqual(999, buffer.Back()); + } + [TestMethod] public void Resample_NonPositiveLength_Throws() { diff --git a/Containers/RingBuffer.cs b/Containers/RingBuffer.cs index c4a0f1f..405b774 100644 --- a/Containers/RingBuffer.cs +++ b/Containers/RingBuffer.cs @@ -267,7 +267,8 @@ public void Resample(int length) for (int i = 0; i < length; i++) { // Map the new index to the old data range - double oldIndex = i * (oldCount - 1) / (double)Math.Max(length - 1, 1); + // Multiply in double: the int product overflows once length * oldCount passes int.MaxValue + double oldIndex = (double)i * (oldCount - 1) / Math.Max(length - 1, 1); int index = (int)Math.Round(oldIndex); // Ensure we don't go out of bounds