Skip to content

RingBuffer.Resample throws IndexOutOfRangeException and loses the buffer's contents for ~46k+ elements (int overflow) #73

Description

@matt-edmondson

What's wrong

RingBuffer<T>.Resample (Containers/RingBuffer.cs, in the resample loop) computes the source index like this:

double oldIndex = i * (oldCount - 1) / (double)Math.Max(length - 1, 1);
int index = (int)Math.Round(oldIndex);
index = Math.Min(index, oldCount - 1);

i * (oldCount - 1) is evaluated in int before the double division. Once (length - 1) * (oldCount - 1) passes int.MaxValue, the product wraps negative, so index comes out negative. Math.Min only clamps the upper end, and oldData[negative] throws.

By then AllocateBuffer(length) has already reset the buffer, so the exception also leaves it half-refilled. The original contents are lost.

Why it matters

The doc comment presents Resample as a tool for time-series and sample-rate changes. One second of 48 kHz audio is 48,000 samples, which is well past the threshold.

Repro:

foreach (int n in new[] { 46340, 46342, 48000 })
{
    var rb = new RingBuffer<int>(Enumerable.Range(0, n), n);
    try { rb.Resample(n); Console.WriteLine($"n={n}: ok"); }
    catch (Exception e) { Console.WriteLine($"n={n}: {e.GetType().Name}; Count={rb.Count} (was {n})"); }
}
// also: new RingBuffer<int>(Enumerable.Range(0, 1000), 1000).Resample(3_000_000) -> IndexOutOfRangeException

Output:

n=46340: ok
n=46342: IndexOutOfRangeException; Count=46341 (was 46342)
n=48000: IndexOutOfRangeException; Count=44741 (was 48000)

Expected: every size succeeds, ending with Count == length and the last element equal to the old last element. The only documented exception is ArgumentOutOfRangeException for length < 1.

Suggested fix

double oldIndex = (double)i * (oldCount - 1) / Math.Max(length - 1, 1);
int index = Math.Clamp((int)Math.Round(oldIndex), 0, oldCount - 1);

Acceptance criteria

  • Resampling a 50,000-element buffer to the same length succeeds, and rb[^1] == 49999.
  • Upsampling 1,000 elements to 3,000,000 succeeds.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions