Skip to content

PauseWriterThreshold and ResumeWriterThreshold options of PipeOptions not validated properly #75166

Closed
@alhimik45

Description

@alhimik45

Description

It is possible to pass values of ResumeWriterThreshold and PauseWriterThreshold that causes program to hang. There is a check that disallows ResumeWriterThreshold to be greater than PauseWriterThreshold (code), but it doesn't work in case when ResumeWriterThreshold left to default -1 value and PauseWriterThreshold passed explicitly and less than DefaultResumeWriterThreshold. In this case options contains ResumeWriterThreshold that greater than PauseWriterThreshold and writer resume never happens.

Similar situation come when passed ResumeWriterThreshold equal to 0. In this case this check is not true even if _unconsumedBytes is zero and writer is not resumed. Not sure is it lack of validation of wrong options value or bug in code that should work with zero value.

Reproduction Steps

Here is small program that successfully completes with correct values and hangs forever in cases described above

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

//correct values for immediate backpressure
// var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: 1));

//using default resumeWriterThreshold gives incorrect combination of values
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: -1));

//with zero resumeWriterThreshold program also hangs
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: 0));

var readTask = Task.Run(async () =>
{
    ReadResult read;
    do
    {
        read = await pipe.Reader.ReadAsync();
        Console.WriteLine($"Read {Encoding.UTF8.GetString(read.Buffer.ToArray())}");
        pipe.Reader.AdvanceTo(read.Buffer.End);
    } while (!read.IsCompleted);
});

var writeTask = Task.Run(async () =>
{
    await pipe.Writer.WriteAsync(Encoding.UTF8.GetBytes("qwerty1"));
    await Task.Delay(100);
    await pipe.Writer.WriteAsync(Encoding.UTF8.GetBytes("qwerty2"));
    await pipe.Writer.CompleteAsync();
});

await Task.WhenAll(readTask, writeTask);

Expected behavior

PipeOptions constructor should throw ArgumentOutOfRangeException for such invalid values

Actual behavior

PipeWriter not resumed after pause

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions