Skip to content

StreamPipeReader never sets IsCompleted if data is buffered  #87984

@davidfowl

Description

@davidfowl

Description

An optimization to return already buffered data in the pipe in StreamPipeReader.ReadAsync means that IsCompleted never gets updated to true even though the next read may be at the end of the stream.

This needs to be removed.

Reproduction Steps

using System.Buffers;
using System.IO.Pipelines;
using System.Text;
using System.Text.Json;

var url = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/8.0/releases.json";

var httpClient = new HttpClient();
using var releaseMessage = await httpClient.GetAsync(url, HttpCompletionOption.ResponseContentRead);
using var release = await releaseMessage.Content.ReadAsStreamAsync();
await ReadStream(release);

async Task ReadStream(Stream stream)
{
    var pipeReader = PipeReader.Create(stream);
    JsonReaderState state = default;

    while (true)
    {
        var result = await pipeReader.ReadAsync();
        var completed = result.IsCompleted;
        
        DoRead(result.Buffer, completed, ref state, out var pos);

        if (completed)
        {
            break;
        }

        pipeReader.AdvanceTo(pos);

    }

    void DoRead(in ReadOnlySequence<byte> text, bool isFinalBlock, ref JsonReaderState state, out SequencePosition position)
    {
        // This is for debugging
        // Console.WriteLine(Encoding.UTF8.GetString(text));

        var reader = new Utf8JsonReader(text, isFinalBlock: isFinalBlock, state);

        while (reader.Read())
        {
            Console.WriteLine(reader.TokenType);
            Console.WriteLine(reader.BytesConsumed);
        }

        position = reader.Position;
        state = reader.CurrentState;
    }
}

Expected behavior

No infinite loop

Actual behavior

The repro has an infinite loop

Regression?

Infinite loop

Known Workarounds

Use a Pipe instead of a StreamPipeReader or know the content length ahead of time.

Configuration

Host:
Version: 8.0.0-preview.5.23268.8
Architecture: x64
Commit: 0f8afd2

.NET SDKs installed:
3.1.426 [C:\Program Files\dotnet\sdk]
6.0.313 [C:\Program Files\dotnet\sdk]
7.0.400-preview.23281.13 [C:\Program Files\dotnet\sdk]
8.0.100-preview.5.23268.17 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.0-preview.5.23268.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0-preview.5.23268.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.18 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.0-preview.5.23268.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions