Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Fix for ZipArchive depending on Position for Create streams#12682

Merged
ianhays merged 3 commits intodotnet:masterfrom
StephenCleary:master
Oct 18, 2016
Merged

Fix for ZipArchive depending on Position for Create streams#12682
ianhays merged 3 commits intodotnet:masterfrom
StephenCleary:master

Conversation

@StephenCleary
Copy link
Contributor

This is a fix for #11497, using the stream wrapper technique suggested by @svick.

The stream wrapper is only applied when necessary (if the ZipArchive is opened in Create mode and the underlying stream does not support seeking).

The wrapper forwards all (non-reading) methods to its base stream, including asynchronous methods. This is important to prevent the wrapper from forcing synchrony.

The existing unit tests (once fixed) were sufficient to detect this bug.

@dnfclas
Copy link

dnfclas commented Oct 15, 2016

Hi @StephenCleary, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas
Copy link

dnfclas commented Oct 15, 2016

@StephenCleary, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@karelz
Copy link
Member

karelz commented Oct 15, 2016

@ianhays can you please CR?

@danmoseley
Copy link
Member

@ianhays PTAL

@ianhays
Copy link
Contributor

ianhays commented Oct 17, 2016

@svick

Looks like goodness to me. I'm somewhat concerned by the overhead of creating the wrapper stream, but considering the old behavior I think it's admissible.

The existing unit tests (once fixed) were sufficient to detect this bug.

@StephenCleary what do you mean by this? We didn't have any tests failing because of this issue. It would be ideal to have a test added that fails with the old behavior but passes with the new behavior.

@StephenCleary
Copy link
Contributor Author

I was also hesitant about the wrapper stream, but the alternative would be to have ZipArchive itself keep track of the position, which would require every helper method using Position to read the stream's position from ZipArchive instead of the stream. I rejected that approach because it's less maintainable - all future zip-related code would "just have to know" that reading stream position is done completely differently here. So I settled on the wrapper, keeping it small, and only using it when necessary.

The first checkin in this pull request fixes the unit tests so that they fail due to this bug. So there are now unit tests that will detect a regression.

@danmoseley
Copy link
Member

@ianhays please hit merge if you're good..

@ianhays
Copy link
Contributor

ianhays commented Oct 18, 2016

Thanks for the contribution @StephenCleary, I tend to agree on this being preferable to manually tracking the position. Merging.

@ianhays ianhays merged commit e8c0e78 into dotnet:master Oct 18, 2016

public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
_position += count;
Copy link
Member

@stephentoub stephentoub Oct 18, 2016

Choose a reason for hiding this comment

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

What if the operation is canceled... won't the position then be incorrect?

Same comment/question would apply as well to exceptions in other operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but what would the correct position be in that case?

Copy link
Contributor

Choose a reason for hiding this comment

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

There's the same issue for when the synchronous Write flat out fails. I considered saying we should update the position after the underlying call, but we would have to do something special for the async Write for that.

Copy link
Member

Choose a reason for hiding this comment

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

but what would the correct position be in that case?

We can't know, but that also means we'd be reporting potentially incorrect results from Position, and I don't know enough about the codebase to know what that could mess up. I'm wondering if on cancellation/failure, we should set _position to a sentinel value (e.g. -1) and change get_Position to do if (_position < 0) throw ...; else return _position;. It may not be worth it if nothing bad would come of it, but we should understand it better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like that idea; it's the only approach that really makes sense.

It also takes this class a step closer to being a generic (read/write) position tracking stream wrapper, which may actually make sense to eventually expose (in a more general package).


namespace System.IO.Compression
{
internal sealed class PositionPreservingWriteOnlyStreamWrapper : Stream
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I'd drop the "Wrapper" suffix. There are a variety of streams that wrap other streams and that don't use a suffix like this, e.g. DeflateStream, BufferedStream, etc.


public override void WriteByte(byte value)
{
_position += 1;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: _position++

@StephenCleary
Copy link
Contributor Author

Pardon my ignorance regarding pull requests, but I'd like to apply the suggestions from @stephentoub. Since this is already merged, that would have to be a new pull request, right?

@ianhays
Copy link
Contributor

ianhays commented Oct 25, 2016

that would have to be a new pull request, right?

Correct.

@jnm2
Copy link

jnm2 commented Nov 11, 2016

I'm pinging here as well because communication on Connect is dodgy.
Can the .NET team confirm how soon this will make it into the full framework?

https://connect.microsoft.com/VisualStudio/feedback/details/816411/ziparchive-shouldnt-read-the-position-of-non-seekable-streams#commentContainer

@karelz karelz modified the milestone: 1.2.0 Dec 3, 2016
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Fix for ZipArchive depending on Position for Create streams

Commit migrated from dotnet/corefx@e8c0e78
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants