Fix RAR5 async decompression corruption in UnpWriteBufAsync

Three bugs in the async version of UnpWriteBuf (used only in the async
decompression path) were causing data corruption when decompressing RAR5
archives containing executable filters (E8/E8E9/ARM) whose blocks spanned
the 4MB write boundary (UNPACK_MAX_WRITE):

1. WrittenFileSize was only incremented inside `if (OutMem != null)`, but
   should always be incremented after ApplyFilter (matching sync behavior).

2. UnpSomeRead = true was missing from the filter processing path.

3. In the NotAllFiltersProcessed else branch (filter intersects write border):
   - WrPtr was not updated to WrittenBorder, corrupting the window pointer
     used to compute WriteBorder on the next flush cycle
   - Remaining filters had NextWindow set to true (inverted logic), when
     sync correctly sets them to false so they are processed next time

All three changes align the async path with the sync UnpWriteBuf logic.
This commit is contained in:
copilot-swe-agent[bot]
2026-08-01 03:40:04 +00:00
committed by GitHub
parent 5445d2b77e
commit 9eb4abe49e
2 changed files with 15 additions and 9 deletions

View File

@@ -3,4 +3,4 @@
"version": "10.0.301",
"rollForward": "disable"
}
}
}

View File

@@ -394,28 +394,34 @@ internal partial class Unpack
{
await UnpIO_UnpWriteAsync(OutMem, 0, BlockLength, cancellationToken)
.ConfigureAwait(false);
WrittenFileSize += BlockLength;
}
UnpSomeRead = true;
WrittenFileSize += BlockLength;
WrittenBorder = BlockEnd;
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
}
}
else
{
NotAllFiltersProcessed = true;
// Current filter intersects the window write border, so we adjust
// the window border to process this filter next time, not now.
WrPtr = WrittenBorder;
// Since Filter start position can only increase, we quit processing
// all following filters for this data block and reset 'NextWindow'
// flag for them.
for (var J = I; J < Filters.Count; J++)
{
var fltj = Filters[J];
if (
fltj.Type != FILTER_NONE
&& fltj.NextWindow == false
&& ((fltj.BlockStart - WrPtr) & MaxWinMask) < FullWriteSize
)
if (fltj.Type != FILTER_NONE)
{
fltj.NextWindow = true;
fltj.NextWindow = false;
}
}
// Do not write data left after current filter now.
NotAllFiltersProcessed = true;
break;
}
}