mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Fix infinite loop in SourceStream.Seek for malformed archives
- Add detection for when SetStream fails during Seek operation - Throw InvalidOperationException with clear error message instead of looping infinitely - Add test case Rar_MalformedArchive_NoInfiniteLoop to validate fix - All 74 RAR archive tests pass Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
This commit is contained in:
@@ -222,8 +222,26 @@ public partial class SourceStream : Stream, IStreamStack
|
||||
SetStream(0);
|
||||
while (_prevSize + Current.Length < pos)
|
||||
{
|
||||
_prevSize += Current.Length;
|
||||
SetStream(_stream + 1);
|
||||
var currentLength = Current.Length;
|
||||
var currentStreamIndex = _stream;
|
||||
_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}."
|
||||
);
|
||||
}
|
||||
|
||||
// Check if we're making progress (stream changed or has non-zero length)
|
||||
if (_stream == currentStreamIndex && currentLength == 0)
|
||||
{
|
||||
// Stream didn't change and has zero length - infinite loop detected
|
||||
throw new InvalidOperationException(
|
||||
$"Cannot seek to position {pos}. Stream has zero length and no next stream available."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -721,4 +721,38 @@ public class RarArchiveTests : ArchiveTests
|
||||
// Verify the exception message matches our expectation
|
||||
Assert.Contains("unpacked file size does not match header", exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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/XXX
|
||||
/// </summary>
|
||||
[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<InvalidOperationException>(() =>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
tests/TestArchives/Archives/Rar.malformed_512byte.rar
Normal file
BIN
tests/TestArchives/Archives/Rar.malformed_512byte.rar
Normal file
Binary file not shown.
Reference in New Issue
Block a user