-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[release/9.0] Fix DeflateStream.FlushAsync if no data has been written #121798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/9.0-staging
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes a regression in DeflateStream.FlushAsync that produces invalid compressed bytes when the method is called without writing any data first. The fix prevents flushing the deflater when no bytes have been written, while still flushing the underlying stream.
Key changes:
- Wrap deflater flush logic in a
_wroteBytescheck to prevent invalid output on empty streams - Underlying stream flush remains unconditional to preserve expected flush behavior
| if (_wroteBytes) | ||
| { | ||
| int compressedBytes; | ||
| flushSuccessful = _deflater.Flush(_buffer, out compressedBytes); | ||
| if (flushSuccessful) | ||
| // Compress any bytes left: | ||
| await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false); | ||
|
|
||
| // Pull out any bytes left inside deflater: | ||
| bool flushSuccessful; | ||
| do | ||
| { | ||
| await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, compressedBytes), cancellationToken).ConfigureAwait(false); | ||
| } | ||
| Debug.Assert(flushSuccessful == (compressedBytes > 0)); | ||
| } while (flushSuccessful); | ||
| int compressedBytes; | ||
| flushSuccessful = _deflater.Flush(_buffer, out compressedBytes); | ||
| if (flushSuccessful) | ||
| { | ||
| await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, compressedBytes), cancellationToken).ConfigureAwait(false); | ||
| } | ||
| Debug.Assert(flushSuccessful == (compressedBytes > 0)); | ||
| } while (flushSuccessful); | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The entire deflater flush block is indented one level deeper, but the comment on line 225 still says 'Compress any bytes left' which may be slightly misleading when _wroteBytes is false and no compression occurs. Consider updating the comment to clarify the conditional nature, such as '// Compress any bytes left if data was written:'
Fixes #121710.
Customer Impact
Certain valid code patterns using DeflateStream and GZipStream may produce invalid bytes when compressing empty input. The invalid output then cannot be correctly decompressed by 3rd party tools.
Workarounds are either not using async path or ensuring FlushAsync is not called by user code if nothing was written to the stream.
Regression
Behavior differs w.r.t. .NET 8.
The bug has been fixed for .NET 11 by #118570
Testing
Tested scenario reported by customer. Additional validation is provided by CI
Risk
Low, fix is small and the root cause is well understood.