Skip to content

Fix edge cases with 1-byte reads#1282

Open
kenkendk wants to merge 6 commits into
adamhathcock:masterfrom
kenkendk:bugfix/single-byte-reads
Open

Fix edge cases with 1-byte reads#1282
kenkendk wants to merge 6 commits into
adamhathcock:masterfrom
kenkendk:bugfix/single-byte-reads

Conversation

@kenkendk

@kenkendk kenkendk commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

This PR fixes a missing overload for ReadByte() that caused the library to return incorrect results when reading a stream with ReadByte().

As the use of ReadByte() on a compressed stream is arguably seldom used, I opted for a simple "read into 1-byte array" solution that is not terribly resource efficient, but prevents having code replicated from the main Read() method into ReadByte().

Unfortunately, the main Read() method also had issues when reading into a 1-byte array, so that was fixed as well.

Added a set of tests that explain the issue and fail before the fix, but succeeds after.

These are clearly edge case, but if anyone passes a compressed stream to another library, even these edge cases should work correctly.

…y to return incorrect results when reading a stream with `ReadByte()`.

As the use of `ReadByte()` on a compressed stream is arguably seldom used, I opted for a simple "read into 1-byte array" solution that is not terribly resource efficient, but prevents having code replicated from the main `Read()` method into `ReadByte()`.

Unfortunately, the main `Read()` method also had issues when reading into a 1-byte array, so that was fixed as well.

Added a set of tests that explain the issue and fail before the fix, but succeeds after.

These are clearly edge case, but if anyone passes a compressed stream to another library, event these edge cases should work correctly.
Copilot AI review requested due to automatic review settings April 13, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect behavior when consuming deflated ZIP entry streams via Stream.ReadByte() / 1-byte Read() calls by correcting end-of-stream handling in ZlibBaseStream, and adds regression tests to cover byte-by-byte and buffered read roundtrips across both Archive and Reader APIs.

Changes:

  • Add ZlibBaseStream.ReadByte() override that delegates to Read() and returns -1 on EOF.
  • Fix ZlibBaseStream.Read(...) / ReadAsync(...) logic to avoid misinterpreting a 1-byte read result as Z_STREAM_END, preventing spurious rewinds.
  • Add ZIP deflate roundtrip tests validating both buffered (CopyTo) and byte-by-byte (ReadByte) extraction paths.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tests/SharpCompress.Test/Zip/ZipCompressionRoundtripTests.cs Adds regression coverage for buffered vs. byte-by-byte reads through Archive and Reader APIs.
src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs Fixes 1-byte read edge cases by overriding ReadByte() and preserving the zlib result code before converting rc to byte count.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/SharpCompress.Test/Zip/ZipCompressionRoundtripTests.cs Outdated
Comment thread tests/SharpCompress.Test/Zip/ZipCompressionRoundtripTests.cs Outdated
Copilot AI review requested due to automatic review settings April 13, 2026 14:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/Providers/Default/GZipCompressionProvider.cs Outdated
Comment thread src/SharpCompress/IO/IStreamStack.cs Outdated
Copilot AI review requested due to automatic review settings April 13, 2026 15:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/SharpCompress.Test/Zip/ZipCompressionRoundtripTests.cs Outdated
@adamhathcock

Copy link
Copy Markdown
Owner

Thanks for finding this. I'm mainly nervous around its usage and the using Read() on an asynchronous stream.

I have tests that only use the async version to prove things.

I'm wondering if it's best to just have the ReadByte throw an exception and have the Read and ReadAsync methods work with single bytes

@kenkendk

Copy link
Copy Markdown
Contributor Author

@adamhathcock Not sure I understand the concern. The ReadByte() method calls Read() and both are sync methods, so no change there?

@adamhathcock

Copy link
Copy Markdown
Owner

but there isn't a ReadByte for the async path. Since ReadByte reuses the sync path, it would fail on asynchronous operations/tests.

@adamhathcock

adamhathcock commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Added the bug here: #1346

Tempted to just make ZLibStream.ReadByte return -1

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.

3 participants