Fix bounds, memory protection, and completion race in core helpers
- AllocatedMemory.Read<T>/Write<T>/ReadBytes/WriteBytes now validate that the requested byte range stays within the allocated block before calling into the memory accessor. - Patch.Apply/Remove temporarily changes the target page to read-write and restores the original protection, mirroring the Detour behavior. - MainThreadPump.WorkItem uses TrySetResult/TrySetException and swallows the InvalidOperationException raised when a completion source is already completed, preventing Dispose from failing during concurrent pump drainage. Regression tests added for all three fixes. Tests: 206 passing, 4 skipped.
This commit is contained in:
@@ -86,12 +86,18 @@ public sealed class AllocatedMemory : IDisposable
|
||||
public IntPtr AddressOf(string name)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
int offset = GetRegionOffset(name);
|
||||
return _baseAddress + offset;
|
||||
}
|
||||
|
||||
private int GetRegionOffset(string name)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(name);
|
||||
|
||||
if (!_regions.TryGetValue(name, out int offset))
|
||||
throw new ArgumentException($"Region '{name}' does not exist.", nameof(name));
|
||||
|
||||
return _baseAddress + offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,8 +111,12 @@ public sealed class AllocatedMemory : IDisposable
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
IntPtr address = AddressOf(name);
|
||||
return _memory.Read<T>(address);
|
||||
int offset = GetRegionOffset(name);
|
||||
int size = Marshal.SizeOf<T>();
|
||||
if (offset > _size - size)
|
||||
throw new ArgumentOutOfRangeException(nameof(name), $"Region '{name}' read of {size} bytes exceeds allocation size {_size}.");
|
||||
|
||||
return _memory.Read<T>(_baseAddress + offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,8 +131,12 @@ public sealed class AllocatedMemory : IDisposable
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
IntPtr address = AddressOf(name);
|
||||
return _memory.Write(address, value);
|
||||
int offset = GetRegionOffset(name);
|
||||
int size = Marshal.SizeOf<T>();
|
||||
if (offset > _size - size)
|
||||
throw new ArgumentOutOfRangeException(nameof(name), $"Region '{name}' write of {size} bytes exceeds allocation size {_size}.");
|
||||
|
||||
return _memory.Write(_baseAddress + offset, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,8 +150,12 @@ public sealed class AllocatedMemory : IDisposable
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
IntPtr address = AddressOf(name);
|
||||
return _memory.ReadBytes(address, count);
|
||||
int offset = GetRegionOffset(name);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(count);
|
||||
if (offset > _size - count)
|
||||
throw new ArgumentOutOfRangeException(nameof(count), $"Region '{name}' read of {count} bytes exceeds allocation size {_size}.");
|
||||
|
||||
return _memory.ReadBytes(_baseAddress + offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,8 +169,11 @@ public sealed class AllocatedMemory : IDisposable
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
IntPtr address = AddressOf(name);
|
||||
return _memory.WriteBytes(address, bytes);
|
||||
int offset = GetRegionOffset(name);
|
||||
if (offset > _size - bytes.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), $"Region '{name}' write of {bytes.Length} bytes exceeds allocation size {_size}.");
|
||||
|
||||
return _memory.WriteBytes(_baseAddress + offset, bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user