Skip to content
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

More helpful exception when compressing large files in seek mode #43542

Open
carlossanlop opened this issue Oct 16, 2020 · 6 comments
Open

More helpful exception when compressing large files in seek mode #43542

carlossanlop opened this issue Oct 16, 2020 · 6 comments
Labels
area-System.IO.Compression help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@carlossanlop
Copy link
Member

carlossanlop commented Oct 16, 2020

When the user opens a stream in Create mode, and passes it to a ZipArchive opened in Update mode, then attempts to add a very large file to the zip, an exception will be thrown on dispose stating Stream was too long, which is confusing for the user, and frustrating if the file was large and this happens so late.

The exception is thrown because we restrict the size of a file to Int32.MaxValue. The restriction is reached because the Update mode requires a stream that allows seeking, so we internally create a MemoryStream so that we can update the archive, but the size limit for the file is Int32.MaxValue.

We do have it documented here, but it's not very obvious for the user to look for answers in that location.

We should explore two improvements:

  1. Throw a more helpful error message when this combination of conditions meet (Stream in Create mode, ZipArchive in Update mode, file too large).
  2. Try to detect this case much earlier, instead of waiting it to happen on Dispose.

I also opened to suggest a Roslyn analyzer that would help users avoid falling into this: #35815

This has been reported a few times already:

/cc @ericstj

@carlossanlop carlossanlop added area-System.IO.Compression help wanted [up-for-grabs] Good issue for external contributors labels Oct 16, 2020
@carlossanlop carlossanlop added this to the 6.0.0 milestone Oct 16, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Oct 16, 2020
@carlossanlop carlossanlop removed the untriaged New issue has not been triaged by the area owner label Oct 16, 2020
@adamsitnik adamsitnik modified the milestones: 6.0.0, 7.0.0 Jul 26, 2021
@WinCPP
Copy link
Contributor

WinCPP commented Jan 9, 2022

@carlossanlop I am contributing after a long time and would like to attempt this.

@danmoseley
Copy link
Member

@WinCPP welcome back! I will assign this to you. Let us know if you need help.

@WinCPP
Copy link
Contributor

WinCPP commented Jan 14, 2022

@WinCPP welcome back! I will assign this to you. Let us know if you need help.

Thanks! And yes, I do need help 🙂

As per the documentation, the file to be added to an archive in update mode cannot be larger than Int32.MaxValue in size. However, the following exception is thrown even when the size is Int32.MaxValue - 1.

      Message: 
System.OutOfMemoryException : Array dimensions exceeded supported range.

      Stack Trace: 
MemoryStream.set_Capacity(Int32 value) line 288
MemoryStream.EnsureCapacity(Int32 value) line 165
MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) line 626
WrappedStream.Write(Byte[] buffer, Int32 offset, Int32 count) line 155
Stream.CopyTo(Stream destination, Int32 bufferSize) line 72
BufferedFileStreamStrategy.CopyTo(Stream destination, Int32 bufferSize) line 945
FileStream.CopyTo(Stream destination, Int32 bufferSize) line 508
Stream.CopyTo(Stream destination) line 51
ZipFileExtensions.DoCreateEntryFromFile(ZipArchive destination, String sourceFileName, String entryName, Nullable`1 compressionLevel) line 123
ZipFileExtensions.CreateEntryFromFile(ZipArchive destination, String sourceFileName, String entryName, CompressionLevel compressionLevel) line 78
ZipFile_ZipArchive_Create.CreateEntryFromLargeFileArchiveUpdateExtension(Boolean withCompressionLevel) line 52

Here is the line that causes the exception (link).

image

Digging more, I found this discussion about mscorlib code over here. that mentions that the max possible index for a byte array is 0x7FFFFFC7 although the max size can be Int32.MaxValue. When I try with a file of size 0x7FFFFFC7 it works fine, but just a byte more i.e. 0x7FFFFFC8 and I get the above-mentioned exception. So should the logic for this fix use 0x7FFFFFC7 as the maximum allowable size instead of Int32.MaxValue? Appreciate your inputs.

image

@jeffhandley jeffhandley modified the milestones: 7.0.0, 8.0.0 Jul 9, 2022
@jeffhandley
Copy link
Member

Digging more, I found this discussion about mscorlib code over here. that mentions that the max possible index for a byte array is 0x7FFFFFC7 although the max size can be Int32.MaxValue. When I try with a file of size 0x7FFFFFC7 it works fine, but just a byte more i.e. 0x7FFFFFC8 and I get the above-mentioned exception. So should the logic for this fix use 0x7FFFFFC7 as the maximum allowable size instead of Int32.MaxValue? Appreciate your inputs.

Hi @WinCPP. I'm sorry we missed your question here. I agree with your assessment here that we should cap the size to 0x7FFFFFC7 instead of Int32.MaxValue. Let us know if you would still like to contribute to this.

@WinCPP
Copy link
Contributor

WinCPP commented Oct 22, 2022

Hi, @jeffhandley thanks for the reply. I am busy with some office work ATM. So I am fine if someone wants to take this ahead.

@jeffhandley
Copy link
Member

Thanks, @WinCPP. And sorry again we missed your question earlier this year.

@ViktorHofer ViktorHofer modified the milestones: 8.0.0, Future Jul 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.IO.Compression help wanted [up-for-grabs] Good issue for external contributors
Projects
None yet
Development

No branches or pull requests

7 participants