You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Modifying a RingBuffer during foreach silently skips or repeats elements instead of throwing #86
RingBuffer<T>.GetEnumerator() (Containers/RingBuffer.cs, ~line 288) is a plain for (i < Count) yield return At(i) loop with no version check. #70 / PR #84 added fail-fast, versioned enumerators to the other array-backed containers (Contiguous*, OrderedMap, InsertionOrderMap). The List-backed containers were already fail-fast, so RingBuffer is now the only container whose enumerator is not.
Failure scenario
On a full buffer, PushBack advances the front index, which shifts every logical index by one:
varrb=newRingBuffer<int>([1,2,3,4],4);foreach(varxinrb){seen.Add(x);if(x==1)rb.PushBack(5);}// seen = 1, 3, 4, 5: element 2 is skipped, and no exception is thrown
Calling rb.Resample(8) inside the same loop gives 1,1,2,2,3,3,4,4, again with no exception. Walking a sliding window while a producer pushes is a common way to use a ring buffer, so it is easy to read corrupted data this way without noticing.
Both cases were confirmed with a temporary MSTest against main (84bb8c4).
Suggested fix
Follow ContiguousCollection:
add a version field and increment it in PushBack, Clear, and AllocateBuffer, which covers Resize and Resample
change GetEnumerator to => Enumerate(version) and call Enumeration.ThrowIfModified(expected, version) before each yield and after the loop
Acceptance:PushBack, Clear, Resize or Resample called during a foreach throws InvalidOperationException, and a test covers each case.
Priority: Medium. Modifying a collection during enumeration is caller misuse, but RingBuffer is now the only container that does not fail fast, and a sliding-window read while pushing is a common way to use it. The pattern to copy already exists.
Activity
matt-edmondson commentedon Sep 28, 2026
Triage
Containers/RingBuffer.cs(GetEnumerator,PushBack,Clear,AllocateBuffer)versionfield bumped by the mutating paths, and route enumeration throughEnumeration.ThrowIfModified. Add tests for each mutator.Generated by Claude Code