Fix dispatcher crash/deadlock, instruction analyzer, cache equality, task leak, and redirection protection
- MainThreadDispatcher: guard DispatchHook with try/catch so exceptions never escape to native caller; drain and fault pending work on Dispose; synchronize Execute/ExecuteAsync/Dispose against race/dispose. - InstructionAnalyzer: require ModRM 0xEC for 0x83/0x81 sub-esp/rsp forms, rejecting unsafe RIP-relative or memory forms. - PatternScannerCache: implement value equality on CacheKey so repeated scans actually hit cache. - BackgroundTaskExecutor: add remote allocations to the free list immediately after VirtualAllocEx, before any write that could fail and leak. - redirect: capture and restore original page protection in Apply/Remove instead of leaving target RWX. - Regression tests for all six fixes. Tests: 198 passing, 4 integration/interactive skipped.
This commit is contained in:
@@ -275,4 +275,64 @@ public class HookingTests
|
||||
NativeMethods.VirtualFreeEx(reader.Handle, allocation, 0, MemoryFreeType.Release);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MainThreadPump_dispose_faults_pending_work()
|
||||
{
|
||||
using var reader = CreateReader();
|
||||
|
||||
IntPtr targetPtr = AllocateFrameStub(reader, out IntPtr allocation);
|
||||
try
|
||||
{
|
||||
var pump = new WhiteMagic.Execution.MainThreadPump(reader.DetourManager, targetPtr);
|
||||
pump.Install();
|
||||
|
||||
Task<int> pending = pump.ExecuteAsync(() => 42);
|
||||
|
||||
pump.Dispose();
|
||||
|
||||
var ex = await Assert.ThrowsAsync<ObjectDisposedException>(() => pending);
|
||||
Assert.Equal(nameof(WhiteMagic.Execution.MainThreadPump), ex.ObjectName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeMethods.VirtualFreeEx(reader.Handle, allocation, 0, MemoryFreeType.Release);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MainThreadPump_dispose_while_execute_blocked_does_not_deadlock()
|
||||
{
|
||||
using var reader = CreateReader();
|
||||
|
||||
IntPtr targetPtr = AllocateFrameStub(reader, out IntPtr allocation);
|
||||
try
|
||||
{
|
||||
var pump = new WhiteMagic.Execution.MainThreadPump(reader.DetourManager, targetPtr);
|
||||
pump.Install();
|
||||
|
||||
// Start Execute on another thread; it will block until Dispose drains the queue.
|
||||
Task executeTask = Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
pump.Execute<int>(() => 42);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
// Give Execute time to pass the gate and block on the TCS.
|
||||
await Task.Delay(50);
|
||||
pump.Dispose();
|
||||
|
||||
Task completed = await Task.WhenAny(executeTask, Task.Delay(TimeSpan.FromSeconds(2)));
|
||||
Assert.Same(executeTask, completed);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeMethods.VirtualFreeEx(reader.Handle, allocation, 0, MemoryFreeType.Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user