From 6de738ff17da4d44c0d7ba32039dfa1f4d5d0622 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 22 Oct 2025 08:32:19 +0100 Subject: [PATCH 1/4] reduce dynamic stackallocs in unpackv1 --- .../Compressors/Rar/UnpackV1/Unpack.cs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index c4e6d108..3afa4caa 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -1028,7 +1028,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable vmCode.Add((byte)(GetBits() >> 8)); AddBits(8); } - return (AddVMCode(FirstByte, vmCode, Length)); + return AddVMCode(FirstByte, vmCode); } private bool ReadVMCodePPM() @@ -1073,10 +1073,10 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable } vmCode.Add((byte)Ch); // VMCode[I]=Ch; } - return (AddVMCode(FirstByte, vmCode, Length)); + return AddVMCode(FirstByte, vmCode); } - private bool AddVMCode(int firstByte, List vmCode, int length) + private bool AddVMCode(int firstByte, List vmCode) { var Inp = new BitInput(); Inp.InitBitInput(); @@ -1199,19 +1199,28 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable { return (false); } - Span VMCode = stackalloc byte[VMCodeSize]; - for (var I = 0; I < VMCodeSize; I++) - { - if (Inp.Overflow(3)) - { - return (false); - } - VMCode[I] = (byte)(Inp.GetBits() >> 8); - Inp.AddBits(8); - } - // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); - rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + var VMCode = ArrayPool.Shared.Rent(VMCodeSize); + try + { + for (var I = 0; I < VMCodeSize; I++) + { + if (Inp.Overflow(3)) + { + return (false); + } + + VMCode[I] = (byte)(Inp.GetBits() >> 8); + Inp.AddBits(8); + } + + // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + } + finally + { + ArrayPool.Shared.Return(VMCode); + } } StackFilter.Program.AltCommands = Filter.Program.Commands; // StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; StackFilter.Program.CommandCount = Filter.Program.CommandCount; From 01021e102b9bd12e13355e66f9f912cbc871315c Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 22 Oct 2025 08:36:03 +0100 Subject: [PATCH 2/4] remove some extra stackallocs --- src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 3afa4caa..4ebfbac2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -205,9 +205,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable private void Unpack29(bool solid) { - Span DDecode = stackalloc int[PackDef.DC]; - Span DBits = stackalloc byte[PackDef.DC]; - int Bits; if (DDecode[1] == 0) From 36c06c4089c8df94d40566ae866476bd8159ccc0 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 22 Oct 2025 09:32:19 +0100 Subject: [PATCH 3/4] ugh, this is used because it shadows a field --- src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 4ebfbac2..3afa4caa 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -205,6 +205,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable private void Unpack29(bool solid) { + Span DDecode = stackalloc int[PackDef.DC]; + Span DBits = stackalloc byte[PackDef.DC]; + int Bits; if (DDecode[1] == 0) From 74e27c028eadc73222f863c6cf1d72fb55af1b58 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 22 Oct 2025 10:10:07 +0100 Subject: [PATCH 4/4] fix the span length --- src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs | 2 +- src/SharpCompress/Compressors/Rar/VM/RarVM.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 3afa4caa..47904984 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -1215,7 +1215,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable } // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); - rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + rarVM.prepare(VMCode.AsSpan(0, VMCodeSize), Filter.Program); } finally { diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index f1ef3834..ce267bad 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -776,9 +776,10 @@ internal sealed class RarVM : BitInput } } - public void prepare(ReadOnlySpan code, int codeSize, VMPreparedProgram prg) + public void prepare(ReadOnlySpan code, VMPreparedProgram prg) { InitBitInput(); + var codeSize = code.Length; var cpLength = Math.Min(MAX_SIZE, codeSize); // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); @@ -795,7 +796,7 @@ internal sealed class RarVM : BitInput prg.CommandCount = 0; if (xorSum == code[0]) { - var filterType = IsStandardFilter(code, codeSize); + var filterType = IsStandardFilter(code); if (filterType != VMStandardFilters.VMSF_NONE) { var curCmd = new VMPreparedCommand(); @@ -1105,7 +1106,7 @@ internal sealed class RarVM : BitInput } } - private VMStandardFilters IsStandardFilter(ReadOnlySpan code, int codeSize) + private VMStandardFilters IsStandardFilter(ReadOnlySpan code) { VMStandardFilterSignature[] stdList = {