Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2022-11-03 03:25:15 +0300
committerGitHub <noreply@github.com>2022-11-03 03:25:15 +0300
commit00d3109a0ead8b11243ee8544ab820e2d60df286 (patch)
tree6564132185715b8a7366b999896f8a57b2552cef
parent328f53c8ccb56906c12ffe5e1dec3cf54b4c5044 (diff)
[release/7.0] Fix unzipping 4GB+ zip files (#77605)
* add a failing test * fix * extend the test to verify more, move it to outerloop as it takes a LOT of time to execute it * test fewer things, but way faster so the test can be run more frequently * add a comment * address code review feedback * use temp directory for temporary test files * address code review feedback Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com>
-rw-r--r--src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs41
-rw-r--r--src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj2
-rw-r--r--src/libraries/System.IO.Compression/tests/ZipArchive/zip_LargeFiles.cs48
3 files changed, 83 insertions, 8 deletions
diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
index 44511243b5e..fb186dfcfc9 100644
--- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
+++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
@@ -199,30 +199,55 @@ namespace System.IO.Compression
if (extraField.Size < sizeof(long))
return true;
- long value64 = reader.ReadInt64();
+ // Advancing the stream (by reading from it) is possible only when:
+ // 1. There is an explicit ask to do that (valid files, corresponding boolean flag(s) set to true).
+ // 2. When the size indicates that all the information is available ("slightly invalid files").
+ bool readAllFields = extraField.Size >= sizeof(long) + sizeof(long) + sizeof(long) + sizeof(int);
+
if (readUncompressedSize)
- zip64Block._uncompressedSize = value64;
+ {
+ zip64Block._uncompressedSize = reader.ReadInt64();
+ }
+ else if (readAllFields)
+ {
+ _ = reader.ReadInt64();
+ }
if (ms.Position > extraField.Size - sizeof(long))
return true;
- value64 = reader.ReadInt64();
if (readCompressedSize)
- zip64Block._compressedSize = value64;
+ {
+ zip64Block._compressedSize = reader.ReadInt64();
+ }
+ else if (readAllFields)
+ {
+ _ = reader.ReadInt64();
+ }
if (ms.Position > extraField.Size - sizeof(long))
return true;
- value64 = reader.ReadInt64();
if (readLocalHeaderOffset)
- zip64Block._localHeaderOffset = value64;
+ {
+ zip64Block._localHeaderOffset = reader.ReadInt64();
+ }
+ else if (readAllFields)
+ {
+ _ = reader.ReadInt64();
+ }
if (ms.Position > extraField.Size - sizeof(int))
return true;
- int value32 = reader.ReadInt32();
if (readStartDiskNumber)
- zip64Block._startDiskNumber = value32;
+ {
+ zip64Block._startDiskNumber = reader.ReadInt32();
+ }
+ else if (readAllFields)
+ {
+ _ = reader.ReadInt32();
+ }
// original values are unsigned, so implies value is too big to fit in signed integer
if (zip64Block._uncompressedSize < 0) throw new InvalidDataException(SR.FieldTooBigUncompressedSize);
diff --git a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
index 229119e3aa3..ef1862eb0bf 100644
--- a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
+++ b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
@@ -24,6 +24,7 @@
<Compile Include="ZipArchive\zip_InvalidParametersAndStrangeFiles.cs" />
<Compile Include="ZipArchive\zip_ManualAndCompatibilityTests.cs" />
<Compile Include="ZipArchive\zip_netcoreappTests.cs" />
+ <Compile Include="ZipArchive\zip_LargeFiles.cs" />
<Compile Include="ZipArchive\zip_ReadTests.cs" />
<Compile Include="ZipArchive\zip_UpdateTests.cs" />
<Compile Include="ZipArchive\zip_UpdateTests.Comments.cs" />
@@ -36,6 +37,7 @@
<Compile Include="$(CommonTestPath)System\IO\Compression\StreamHelpers.cs" Link="Common\System\IO\Compression\StreamHelpers.cs" />
<Compile Include="$(CommonTestPath)System\IO\TempFile.cs" Link="Common\System\IO\TempFile.cs" />
<Compile Include="$(CommonTestPath)System\IO\Compression\ZipTestHelper.cs" Link="Common\System\IO\Compression\ZipTestHelper.cs" />
+ <Compile Include="$(CommonTestPath)TestUtilities\System\DisableParallelization.cs" Link="Common\TestUtilities\System\DisableParallelization.cs" />
<Compile Include="$(CommonPath)System\Threading\Tasks\TaskToApm.cs" Link="Common\System\Threading\Tasks\TaskToApm.cs" />
<Compile Include="$(CommonTestPath)System\IO\ConnectedStreams.cs" Link="Common\System\IO\ConnectedStreams.cs" />
<Compile Include="$(CommonPath)System\Net\MultiArrayBuffer.cs" Link="ProductionCode\Common\System\Net\MultiArrayBuffer.cs" />
diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_LargeFiles.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_LargeFiles.cs
new file mode 100644
index 00000000000..d240a176b2b
--- /dev/null
+++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_LargeFiles.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Compression.Tests
+{
+ [Collection(nameof(DisableParallelization))]
+ public class zip_LargeFiles : ZipFileTestBase
+ {
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
+ [OuterLoop("It requires almost 12 GB of free disk space")]
+ public static void UnzipOver4GBZipFile()
+ {
+ byte[] buffer = GC.AllocateUninitializedArray<byte>(1_000_000_000); // 1 GB
+
+ string zipArchivePath = Path.Combine(Path.GetTempPath(), "over4GB.zip");
+ DirectoryInfo tempDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "over4GB"));
+
+ try
+ {
+ for (byte i = 0; i < 6; i++)
+ {
+ File.WriteAllBytes(Path.Combine(tempDir.FullName, $"{i}.test"), buffer);
+ }
+
+ ZipFile.CreateFromDirectory(tempDir.FullName, zipArchivePath, CompressionLevel.NoCompression, includeBaseDirectory: false);
+
+ using ZipArchive zipArchive = ZipFile.OpenRead(zipArchivePath);
+ foreach (ZipArchiveEntry entry in zipArchive.Entries)
+ {
+ using Stream entryStream = entry.Open();
+
+ Assert.True(entryStream.CanRead);
+ Assert.Equal(buffer.Length, entryStream.Length);
+ }
+ }
+ finally
+ {
+ File.Delete(zipArchivePath);
+
+ tempDir.Delete(recursive: true);
+ }
+ }
+ }
+}