-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
PipeReaderStream's HandleReadResult implementation calls AdvanceTo with the examined argument set to the same value as consumed.
runtime/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderStream.cs
Line 142 in ac663e4
| _pipeReader.AdvanceTo(consumed); |
If the user previously advanced the pipe's
examined beyond what is read via the stream, the read will throw.
Reproduction Steps
using System.Buffers;
using System.IO.Pipelines;
var pipe = new Pipe();
pipe.Writer.Write("abc"u8);
await pipe.Writer.FlushAsync();
pipe.Reader.TryRead(out var result);
pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.Slice(result.Buffer.Start, 2).End);
_ = pipe.Reader.AsStream().ReadByte();Expected behavior
ReadByte returns 'a', advances the pipe's consumed by 1, leaving examined at 2.
Actual behavior
Throws
System.InvalidOperationException: The examined position cannot be less than the previously examined position.
at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_InvalidExaminedPosition()
at System.IO.Pipelines.Pipe.AdvanceReader(BufferSegment consumedSegment, Int32 consumedIndex, BufferSegment examinedSegment, Int32 examinedIndex)
at System.IO.Pipelines.Pipe.AdvanceReader(SequencePosition& consumed, SequencePosition& examined)
at System.IO.Pipelines.PipeReaderStream.HandleReadResult(ReadResult result, Span`1 buffer)
at System.IO.Pipelines.PipeReaderStream.HandleReadResult(ReadResult result, Span`1 buffer)
at System.IO.Pipelines.PipeReaderStream.ReadInternal(Span`1 buffer)
at System.IO.Pipelines.PipeReaderStream.ReadByte()
Regression?
Not as far as I can tell.
Known Workarounds
Assuming that the examined - start delta is smaller than 4 KB, you can wrap the pipe like so
reader = PipeReader.Create(reader.AsStream());before doing any reads via the AsStream().
If it's above 4 KB, you can increase the buffer size option on PipeReader.Create.
Configuration
No response
Other information
ASP.NET Core's DuplexPipeStream implementation has the same issue
https://github.com/dotnet/aspnetcore/blob/d630c295110bb4af6b49298671024a545c1642bf/src/Shared/ServerInfrastructure/DuplexPipeStream.cs#L148