From 319c003b7b71cc232683b3048c4622ef528fa11e Mon Sep 17 00:00:00 2001 From: Jeremy Powell Date: Fri, 6 Dec 2024 11:41:13 +1300 Subject: [PATCH] Limit V3 compund files to 2 GB --- OpenMcdf.Tests/OpenMcdf.Tests.csproj | 1 + OpenMcdf.Tests/RootStorageTests.cs | 23 ++++++++++++++++++++++- OpenMcdf/RootContext.cs | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/OpenMcdf.Tests/OpenMcdf.Tests.csproj b/OpenMcdf.Tests/OpenMcdf.Tests.csproj index 648240d..105120a 100644 --- a/OpenMcdf.Tests/OpenMcdf.Tests.csproj +++ b/OpenMcdf.Tests/OpenMcdf.Tests.csproj @@ -20,6 +20,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/OpenMcdf.Tests/RootStorageTests.cs b/OpenMcdf.Tests/RootStorageTests.cs index 521eca8..f6350ed 100644 --- a/OpenMcdf.Tests/RootStorageTests.cs +++ b/OpenMcdf.Tests/RootStorageTests.cs @@ -1,4 +1,6 @@ -namespace OpenMcdf.Tests; +using Microsoft.IO; + +namespace OpenMcdf.Tests; [TestClass] public sealed class RootStorageTests @@ -231,4 +233,23 @@ public void DeleteTrimsBaseStream(bool consolidate) Assert.IsTrue(originalLength > newLength); } + + [TestMethod] + [DoNotParallelize] // High memory usage + public void V3ThrowsIOExceptionAt2GB() + { + const long MaxStreamLength = 2L * 1024 * 1024 * 1024; + + RecyclableMemoryStreamManager manager = new(); + using RecyclableMemoryStream baseStream = new(manager); + baseStream.Capacity64 = MaxStreamLength; + + using var rootStorage = RootStorage.Create(baseStream, Version.V3); + using CfbStream stream = rootStorage.CreateStream("Test"); + byte[] buffer = TestData.CreateByteArray(1024 * 1024); + while (baseStream.Length + buffer.Length <= MaxStreamLength) + stream.Write(buffer, 0, buffer.Length); + + Assert.ThrowsException(() => stream.Write(buffer, 0, buffer.Length)); + } } diff --git a/OpenMcdf/RootContext.cs b/OpenMcdf/RootContext.cs index b066534..0898897 100644 --- a/OpenMcdf/RootContext.cs +++ b/OpenMcdf/RootContext.cs @@ -16,6 +16,8 @@ enum IOContextFlags /// internal sealed class RootContext : ContextBase, IDisposable { + const long MaximumV3StreamLength = 2147483648; + readonly IOContextFlags contextFlags; readonly CfbBinaryWriter? writer; readonly TransactedStream? transactedStream; @@ -185,6 +187,9 @@ public void Flush() public void ExtendStreamLength(long length) { + if (Version is Version.V3 && length > MaximumV3StreamLength) + throw new IOException("V3 compound files are limited to 2 GB."); + if (Length < length) Length = length; }