Skip to content

Make ReadOnlySequenceStream non-seekable to match net11 - #580

Merged
SimonCropp merged 1 commit into
mainfrom
readonlysequencestream-non-seekable
Sep 9, 2026
Merged

Make ReadOnlySequenceStream non-seekable to match net11#580
SimonCropp merged 1 commit into
mainfrom
readonlysequencestream-non-seekable

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

ReadOnlySequenceStream shipped seekable in dotnet/runtime#126669, which is what the polyfill was written against. dotnet/runtime#132023 then made it intentionally non-seekable and removed its seek state and traversal logic, so all ten tests failed on the net11 leg while passing everywhere else.

Upstream rationale: backward positioning requires re-walking segments from the start, and ReadOnlySequence segment boundaries can be indirectly controlled by an untrusted network client through packet framing, so repeated seeks are worst case O(N) under adversarial fragmentation.

CanSeek now returns false, and Length, Position and Seek throw NotSupportedException. The long position field and the MoveTo rewind logic are gone; the SequencePosition cursor is the only state and only moves forward. ReadByte, CopyTo and CopyToAsync test remaining.IsEmpty instead of comparing against the sequence length.

Tests replace the six seek based cases with SeekingThrows (all six seek entry points) and ReadsAreForwardOnly (a failed seek must not disturb the cursor); position assertions elsewhere become drain checks.

Verified against the real net11 type with a reflection and behaviour probe. StringStream, ReadOnlyMemoryStream and WritableMemoryStream were checked the same way and already match: StringStream was never seekable, and the two memory streams stay seekable.

ReadOnlySequenceStream shipped seekable in dotnet/runtime#126669, which is
what the polyfill was written against. dotnet/runtime#132023 then made it
intentionally non-seekable and removed its seek state and traversal logic,
so all ten tests failed on the net11 leg while passing everywhere else.

Upstream rationale: backward positioning requires re-walking segments from
the start, and ReadOnlySequence<T> segment boundaries can be indirectly
controlled by an untrusted network client through packet framing, so
repeated seeks are worst case O(N) under adversarial fragmentation.

CanSeek now returns false, and Length, Position and Seek throw
NotSupportedException. The long position field and the MoveTo rewind logic
are gone; the SequencePosition cursor is the only state and only moves
forward. ReadByte, CopyTo and CopyToAsync test remaining.IsEmpty instead of
comparing against the sequence length.

Tests replace the six seek based cases with SeekingThrows (all six seek
entry points) and ReadsAreForwardOnly (a failed seek must not disturb the
cursor); position assertions elsewhere become drain checks.

Verified against the real net11 type with a reflection and behaviour probe.
StringStream, ReadOnlyMemoryStream and WritableMemoryStream were checked the
same way and already match: StringStream was never seekable, and the two
memory streams stay seekable.
@SimonCropp SimonCropp added this to the 11.3.0 milestone Sep 9, 2026
@SimonCropp
SimonCropp merged commit cb1c5ae into main Sep 9, 2026
6 checks passed
@SimonCropp
SimonCropp deleted the readonlysequencestream-non-seekable branch September 9, 2026 01:42
This was referenced Sep 10, 2026
This was referenced Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant