From 13199fcfd14acfe41585d19d8928dec4bdec1336 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Feb 2026 09:28:50 +0000
Subject: [PATCH 1/3] Initial plan
From 8737b7a38e39bcf26e11fd96050748dd191d3f93 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Feb 2026 09:31:38 +0000
Subject: [PATCH 2/3] Apply infinite loop fix to SourceStream.cs and add test
case
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
src/SharpCompress/IO/SourceStream.cs | 22 ++++++++++--
.../SharpCompress.Test/Rar/RarArchiveTests.cs | 34 ++++++++++++++++++
.../Archives/Rar.malformed_512byte.rar | Bin 0 -> 512 bytes
3 files changed, 54 insertions(+), 2 deletions(-)
create mode 100644 tests/TestArchives/Archives/Rar.malformed_512byte.rar
diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs
index 0712d915..606b0fa7 100644
--- a/src/SharpCompress/IO/SourceStream.cs
+++ b/src/SharpCompress/IO/SourceStream.cs
@@ -222,8 +222,26 @@ public class SourceStream : Stream, IStreamStack
SetStream(0);
while (_prevSize + Current.Length < pos)
{
- _prevSize += Current.Length;
- SetStream(_stream + 1);
+ var currentLength = Current.Length;
+ _prevSize += currentLength;
+
+ if (!SetStream(_stream + 1))
+ {
+ // No more streams available, cannot seek to requested position
+ throw new InvalidOperationException(
+ $"Cannot seek to position {pos}. End of stream reached at position {_prevSize}."
+ );
+ }
+
+ // Safety check: if we have a zero-length stream and we're still not
+ // making progress toward the target position, we're in an invalid state
+ if (currentLength == 0 && Current.Length == 0)
+ {
+ // Both old and new stream have zero length - cannot make progress
+ throw new InvalidOperationException(
+ $"Cannot seek to position {pos}. Encountered zero-length streams at position {_prevSize}."
+ );
+ }
}
}
diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
index ba42f649..3e67dbe3 100644
--- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
+++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
@@ -717,4 +717,38 @@ public class RarArchiveTests : ArchiveTests
// Verify the exception message matches our expectation
Assert.Contains("unpacked file size does not match header", exception.Message);
}
+
+ ///
+ /// Test case for malformed RAR archives that previously caused infinite loops.
+ /// This test verifies that attempting to read entries from a potentially malformed
+ /// 512-byte RAR archive throws an InvalidOperationException instead of looping infinitely.
+ /// See: https://github.com/adamhathcock/sharpcompress/issues/1176
+ ///
+ [Fact]
+ public void Rar_MalformedArchive_NoInfiniteLoop()
+ {
+ var testFile = "Rar.malformed_512byte.rar";
+ var readerOptions = new ReaderOptions { LookForHeader = true };
+
+ // This should throw InvalidOperationException, not hang in an infinite loop
+ var exception = Assert.Throws(() =>
+ {
+ using var fileStream = File.Open(
+ Path.Combine(TEST_ARCHIVES_PATH, testFile),
+ FileMode.Open
+ );
+ using IRarArchive rarFile = RarArchive.OpenArchive(fileStream, readerOptions);
+ using IArchive archive = rarFile;
+
+ // Attempting to enumerate entries should throw an exception
+ // instead of looping infinitely
+ foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
+ {
+ // This line should not be reached due to the exception
+ }
+ });
+
+ // Verify that the exception is related to seeking beyond available data
+ Assert.Contains("Cannot seek to position", exception.Message);
+ }
}
diff --git a/tests/TestArchives/Archives/Rar.malformed_512byte.rar b/tests/TestArchives/Archives/Rar.malformed_512byte.rar
new file mode 100644
index 0000000000000000000000000000000000000000..914693f8840453420463ef96e01af7040c8e3ff8
GIT binary patch
literal 512
zcmWGaEK-zWXE;Bhn1O+p0Rm1>s$ytRW=LaTV2EO1U|^b&lD-)vBWuhIq8OZgLwF^x
zocKG3=Y6M-?1Mms{Z~&XX(UE^`~G7-k=tv0`Nw^huB5)UWtv}Q_MNnvcffkX*Ot#p
zh3{sZ?6_;q-@M-Yi0b3?u&{hVr|nbkwfsGEL3FC!|2Z3a)$aOPuHJK4akAXk`deyE
z4_`%<9GGCwU@_5ylYt>ghN-wld-9})L^D}qSq23L28NW(;*yxO%$(HXn54|Sn4;9;
znB@H2-26Pfg2Zfw0}`?U7tTzadqc4C?Qv7#Kofx$CPvtG{0@ohnHdfoX69j>
z{V8!h?}jgaa;Hr9x6%i9^UZFS#QcaZ|gQ$MqmIW{pq
zjpLkhr}k~g{p0WDyElk29)HrjdE&`T(Zbf$LVxB93yTvZ7A0k{Br%+Qc7@OHqQe8d
LXb-iL{-iDdA_?4L
literal 0
HcmV?d00001
From ad7e64ba43028b2b760b1226f1510ccf0b3e5063 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Feb 2026 09:33:37 +0000
Subject: [PATCH 3/3] Fix test to use correct RarArchive API - all RAR tests
passing
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
tests/SharpCompress.Test/Rar/RarArchiveTests.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
index 3e67dbe3..7b6a94b2 100644
--- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
+++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
@@ -737,8 +737,7 @@ public class RarArchiveTests : ArchiveTests
Path.Combine(TEST_ARCHIVES_PATH, testFile),
FileMode.Open
);
- using IRarArchive rarFile = RarArchive.OpenArchive(fileStream, readerOptions);
- using IArchive archive = rarFile;
+ using var archive = RarArchive.Open(fileStream, readerOptions);
// Attempting to enumerate entries should throw an exception
// instead of looping infinitely