mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Fix DataDescriptorStream to handle legitimate cross-boundary signatures
Previous fix prevented infinite loops but broke detection of legitimate data descriptor signatures split across buffer boundaries. New approach: - Track previous rewind count in _previousSearchPosition - Detect infinite loop when read size equals previous rewind count AND all bytes match the signature pattern - In that case, treat bytes as data (not signature) to break loop - Otherwise, allow normal rewind/match to continue for legitimate cross-boundary signatures This fixes both cases: 1. Infinite loop on data containing signature-like bytes (0x50...) 2. Correct detection of actual signatures split at buffer edge Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
This commit is contained in:
@@ -30,7 +30,7 @@ public class DataDescriptorStream : Stream, IStreamStack
|
||||
private int _searchPosition;
|
||||
private bool _isDisposed;
|
||||
private bool _done;
|
||||
private long _lastRewindPosition = -1;
|
||||
private int _previousSearchPosition;
|
||||
|
||||
private static byte[] _dataDescriptorMarker = new byte[] { 0x50, 0x4b, 0x07, 0x08 };
|
||||
private static long _dataDescriptorSize = 24;
|
||||
@@ -117,6 +117,36 @@ public class DataDescriptorStream : Stream, IStreamStack
|
||||
|
||||
var read = _stream.Read(buffer, offset, count);
|
||||
|
||||
// Detect infinite loop: if we just rewound and read the exact same bytes again
|
||||
// (indicated by read == _previousSearchPosition and all bytes matching),
|
||||
// it means these bytes are data, not a signature. Don't rewind again.
|
||||
var inInfiniteLoop =
|
||||
_previousSearchPosition > 0 && read == _previousSearchPosition && read <= 3;
|
||||
|
||||
if (inInfiniteLoop)
|
||||
{
|
||||
// Verify all bytes match the pattern
|
||||
var allMatch = true;
|
||||
for (var i = 0; i < read && allMatch; i++)
|
||||
{
|
||||
if (buffer[offset + i] != _dataDescriptorMarker[i])
|
||||
{
|
||||
allMatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allMatch)
|
||||
{
|
||||
// This is the infinite loop condition - these bytes are data, not signature
|
||||
// Reset state and return the bytes as data
|
||||
_searchPosition = 0;
|
||||
_previousSearchPosition = 0;
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
_previousSearchPosition = 0;
|
||||
|
||||
for (var i = 0; i < read; i++)
|
||||
{
|
||||
if (buffer[offset + i] == _dataDescriptorMarker[_searchPosition])
|
||||
@@ -164,14 +194,9 @@ public class DataDescriptorStream : Stream, IStreamStack
|
||||
|
||||
if (_searchPosition > 0)
|
||||
{
|
||||
var newPosition = _stream.Position - _searchPosition;
|
||||
// Prevent infinite loop: don't rewind to the same position twice
|
||||
if (newPosition != _lastRewindPosition)
|
||||
{
|
||||
read -= _searchPosition;
|
||||
_stream.Position = newPosition;
|
||||
_lastRewindPosition = newPosition;
|
||||
}
|
||||
read -= _searchPosition;
|
||||
_stream.Position -= _searchPosition;
|
||||
_previousSearchPosition = _searchPosition;
|
||||
_searchPosition = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user