fix #1926 integer overflow in BufferReader (make total consumed 64-bit) by mgravell · Pull Request #1928 · StackExchange/StackExchange.Redis
Expand Up
@@ -12,15 +12,16 @@ internal enum ConsumeResult
}
internal ref struct BufferReader
{
private long _totalConsumed;
public int OffsetThisSpan { get; private set; }
public int RemainingThisSpan { get; private set; }
private ReadOnlySequence<byte>.Enumerator _iterator; private ReadOnlySpan<byte> _current;
public ReadOnlySpan<byte> OversizedSpan => _current;
public ReadOnlySpan<byte> SlicedSpan => _current.Slice(OffsetThisSpan, RemainingThisSpan); public int OffsetThisSpan { get; private set; } private int TotalConsumed { get; set; } // hide this; callers should use the snapshot-aware methods instead public int RemainingThisSpan { get; private set; }
public bool IsEmpty => RemainingThisSpan == 0;
Expand Down Expand Up @@ -49,7 +50,7 @@ public BufferReader(ReadOnlySequence<byte> buffer) _lastSnapshotBytes = 0; _iterator = buffer.GetEnumerator(); _current = default; OffsetThisSpan = RemainingThisSpan = TotalConsumed = 0; _totalConsumed = OffsetThisSpan = RemainingThisSpan = 0;
FetchNextSegment(); } Expand Down Expand Up @@ -87,7 +88,7 @@ public bool TryConsume(int count) if (count <= available) { // consume part of this span TotalConsumed += count; _totalConsumed += count; RemainingThisSpan -= count; OffsetThisSpan += count;
Expand All @@ -96,7 +97,7 @@ public bool TryConsume(int count) }
// consume all of this span TotalConsumed += available; _totalConsumed += available; count -= available; } while (FetchNextSegment()); return false; Expand All @@ -110,36 +111,14 @@ public bool TryConsume(int count) // to avoid having to use buffer.Slice on huge ranges private SequencePosition SnapshotPosition() { var consumed = TotalConsumed; var delta = consumed - _lastSnapshotBytes; var delta = _totalConsumed - _lastSnapshotBytes; if (delta == 0) return _lastSnapshotPosition;
SequencePosition pos; try { pos = _buffer.GetPosition(delta, _lastSnapshotPosition); } catch (ArgumentOutOfRangeException ex) { ThrowSnapshotFailure(delta, ex); throw; // should never be reached } _lastSnapshotBytes = consumed; var pos = _buffer.GetPosition(delta, _lastSnapshotPosition); _lastSnapshotBytes = _totalConsumed; return _lastSnapshotPosition = pos; } private void ThrowSnapshotFailure(long delta, Exception innerException) { long length; try { length = _buffer.Length; } catch { length = -1; } throw new ArgumentOutOfRangeException($"Error calculating {nameof(SnapshotPosition)}: {TotalConsumed} of {length}, {_lastSnapshotBytes}+{delta}", innerException); }
public ReadOnlySequence<byte> ConsumeAsBuffer(int count) { if (!TryConsumeAsBuffer(count, out var buffer)) throw new EndOfStreamException(); Expand Down
private ReadOnlySequence<byte>.Enumerator _iterator; private ReadOnlySpan<byte> _current;
public ReadOnlySpan<byte> OversizedSpan => _current;
public ReadOnlySpan<byte> SlicedSpan => _current.Slice(OffsetThisSpan, RemainingThisSpan); public int OffsetThisSpan { get; private set; } private int TotalConsumed { get; set; } // hide this; callers should use the snapshot-aware methods instead public int RemainingThisSpan { get; private set; }
public bool IsEmpty => RemainingThisSpan == 0;
Expand Down Expand Up @@ -49,7 +50,7 @@ public BufferReader(ReadOnlySequence<byte> buffer) _lastSnapshotBytes = 0; _iterator = buffer.GetEnumerator(); _current = default; OffsetThisSpan = RemainingThisSpan = TotalConsumed = 0; _totalConsumed = OffsetThisSpan = RemainingThisSpan = 0;
FetchNextSegment(); } Expand Down Expand Up @@ -87,7 +88,7 @@ public bool TryConsume(int count) if (count <= available) { // consume part of this span TotalConsumed += count; _totalConsumed += count; RemainingThisSpan -= count; OffsetThisSpan += count;
Expand All @@ -96,7 +97,7 @@ public bool TryConsume(int count) }
// consume all of this span TotalConsumed += available; _totalConsumed += available; count -= available; } while (FetchNextSegment()); return false; Expand All @@ -110,36 +111,14 @@ public bool TryConsume(int count) // to avoid having to use buffer.Slice on huge ranges private SequencePosition SnapshotPosition() { var consumed = TotalConsumed; var delta = consumed - _lastSnapshotBytes; var delta = _totalConsumed - _lastSnapshotBytes; if (delta == 0) return _lastSnapshotPosition;
SequencePosition pos; try { pos = _buffer.GetPosition(delta, _lastSnapshotPosition); } catch (ArgumentOutOfRangeException ex) { ThrowSnapshotFailure(delta, ex); throw; // should never be reached } _lastSnapshotBytes = consumed; var pos = _buffer.GetPosition(delta, _lastSnapshotPosition); _lastSnapshotBytes = _totalConsumed; return _lastSnapshotPosition = pos; } private void ThrowSnapshotFailure(long delta, Exception innerException) { long length; try { length = _buffer.Length; } catch { length = -1; } throw new ArgumentOutOfRangeException($"Error calculating {nameof(SnapshotPosition)}: {TotalConsumed} of {length}, {_lastSnapshotBytes}+{delta}", innerException); }
public ReadOnlySequence<byte> ConsumeAsBuffer(int count) { if (!TryConsumeAsBuffer(count, out var buffer)) throw new EndOfStreamException(); Expand Down