From 560550ef96d9307c74658fc9868e0c0b30149a21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:39:47 +0000 Subject: [PATCH 1/3] Initial plan From 46d5b8c35899fe7c1ad06f7c24df06a1d2a73cb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:06:54 +0000 Subject: [PATCH 2/3] Fix Debug.Assert in SubReadStream when reading after seeking past end Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com> --- .../System/IO/Compression/ZipCustomStreams.cs | 6 ++-- .../tests/ZipArchive/zip_ReadTests.cs | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs index 12f41c5740b8cb..92716b8c913200 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs @@ -334,7 +334,7 @@ public override int Read(byte[] buffer, int offset, int count) if (_superStream.Position != _positionInSuperStream) _superStream.Seek(_positionInSuperStream, SeekOrigin.Begin); if (_positionInSuperStream + count > _endInSuperStream) - count = (int)(_endInSuperStream - _positionInSuperStream); + count = (int)Math.Max(0L, _endInSuperStream - _positionInSuperStream); Debug.Assert(count >= 0); Debug.Assert(count <= origCount); @@ -357,7 +357,7 @@ public override int Read(Span destination) if (_superStream.Position != _positionInSuperStream) _superStream.Seek(_positionInSuperStream, SeekOrigin.Begin); if (_positionInSuperStream + count > _endInSuperStream) - count = (int)(_endInSuperStream - _positionInSuperStream); + count = (int)Math.Max(0L, _endInSuperStream - _positionInSuperStream); Debug.Assert(count >= 0); Debug.Assert(count <= origCount); @@ -395,7 +395,7 @@ async ValueTask Core(Memory buffer, CancellationToken cancellationTok if (_positionInSuperStream > _endInSuperStream - buffer.Length) { - buffer = buffer.Slice(0, (int)(_endInSuperStream - _positionInSuperStream)); + buffer = buffer.Slice(0, (int)Math.Max(0L, _endInSuperStream - _positionInSuperStream)); } int ret = await _superStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs index 5218765645a3a7..eeaa61d00c09ca 100644 --- a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs +++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs @@ -889,5 +889,33 @@ public static async Task CompressionMethod_Deflate64_ReturnsDeflate64(bool async Assert.Equal(ZipCompressionMethod.Deflate64, readEntry.CompressionMethod); await DisposeZipArchive(async, readArchive); } + + [Theory] + [MemberData(nameof(Get_Booleans_Data))] + public static async Task ReadAfterSeekingPastEnd_ReturnsZeroBytes(bool async) + { + using var ms = new MemoryStream(); + using (var archive = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true)) + { + var entry = archive.CreateEntry("test.txt", CompressionLevel.NoCompression); + using var stream = entry.Open(); + stream.Write("Hello, World!"u8); + } + + ms.Position = 0; + using var readArchive = await CreateZipArchive(async, ms, ZipArchiveMode.Read); + Stream readStream = await OpenEntryStream(async, readArchive.Entries[0]); + + readStream.Seek(1, SeekOrigin.End); + + byte[] buffer = new byte[1024]; + int bytesRead = async + ? await readStream.ReadAsync(buffer) + : readStream.Read(buffer, 0, buffer.Length); + + Assert.Equal(0, bytesRead); + + await DisposeStream(async, readStream); + } } } From ddae75ce57a820ab8495b68f5b2b49359412ee41 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:30:56 +0000 Subject: [PATCH 3/3] Add Position assertions before and after read in ReadAfterSeekingPastEnd test Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs index eeaa61d00c09ca..c2f856dd88bf96 100644 --- a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs +++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs @@ -907,6 +907,7 @@ public static async Task ReadAfterSeekingPastEnd_ReturnsZeroBytes(bool async) Stream readStream = await OpenEntryStream(async, readArchive.Entries[0]); readStream.Seek(1, SeekOrigin.End); + Assert.Equal(14, readStream.Position); byte[] buffer = new byte[1024]; int bytesRead = async @@ -914,6 +915,7 @@ public static async Task ReadAfterSeekingPastEnd_ReturnsZeroBytes(bool async) : readStream.Read(buffer, 0, buffer.Length); Assert.Equal(0, bytesRead); + Assert.Equal(14, readStream.Position); await DisposeStream(async, readStream); }