Skip to content

Commit

Permalink
Merge pull request #1 from marzent/master
Browse files Browse the repository at this point in the history
Increase `MemoryBufferHelper.Allocate` reliability
  • Loading branch information
Sewer56 authored Apr 13, 2022
2 parents 120040d + 8f0899a commit 64ce6e1
Showing 1 changed file with 26 additions and 21 deletions.
47 changes: 26 additions & 21 deletions Source/Reloaded.Memory.Buffers/MemoryBufferHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,42 +240,47 @@ public MemoryBuffer[] FindBuffers(int size, IntPtr minimumAddress, IntPtr maximu
/// <param name="size">The minimum size of the memory to be allocated.</param>
/// <param name="minimumAddress">The minimum absolute address to allocate in.</param>
/// <param name="maximumAddress">The maximum absolute address to allocate in.</param>
/// <param name="retryCount">In the case the memory allocation fails; the amount of times memory allocation is to be retried.</param>
/// <param name="retryCount">In the case the memory allocation for a potential location fails; the amount of times memory allocation is to be retried.</param>
/// <exception cref="System.Exception">Memory allocation failure due to possible race condition with other process/process itself/Windows scheduling.</exception>
/// <remarks>
/// This function is virtually the same to running <see cref="FindBufferLocation"/> and then running Windows'
/// VirtualAlloc yourself. Except for the extra added safety of mutual exclusion (Mutex).
/// VirtualAlloc yourself. Except for the extra added safety of mutual exclusion (Mutex) and mitigating a wine bug
/// where allocation can fail on the first free pages repeatedly.
/// The memory is allocated with the PAGE_EXECUTE_READWRITE permissions.
/// </remarks>
public BufferAllocationProperties Allocate(int size, int minimumAddress = 0x10000, int maximumAddress = 0x7FFFFFFF, int retryCount = 3)
{
if (minimumAddress <= 0)
throw new ArgumentException("Please do not set the minimum address to 0 or negative. It collides with the return values of Windows API functions" +
"where e.g. 0 is returned on failure but you can also allocate successfully on 0.");
Exception allocationException = new("Failed to allocate memory using VirtualAlloc/ VirtualAllocEx");

// Keep retrying memory allocation.
_allocateMemoryMutex.WaitOne();

try
{
return Run(retryCount, () =>
{
var memoryLocation = FindBufferLocation(size, minimumAddress, maximumAddress, true);
var virtualAllocFunction = VirtualAllocUtility.GetVirtualAllocFunction(Process);
var result = virtualAllocFunction(Process.Handle, memoryLocation.MemoryAddress, (ulong)memoryLocation.Size);

if (result == IntPtr.Zero)
throw new Exception("Failed to allocate memory using VirtualAlloc/VirtualAllocEx");

_allocateMemoryMutex.ReleaseMutex();
return memoryLocation;
});
}
catch (Exception)
{
_allocateMemoryMutex.ReleaseMutex();
throw;
while (minimumAddress < maximumAddress)
{
try
{
return Run(retryCount, () =>
{
var memoryLocation = FindBufferLocation(size, minimumAddress, maximumAddress, true);
var virtualAllocFunction = VirtualAllocUtility.GetVirtualAllocFunction(Process);
var result = virtualAllocFunction(Process.Handle, memoryLocation.MemoryAddress, (ulong)memoryLocation.Size);

if (result == IntPtr.Zero)
throw allocationException;
_allocateMemoryMutex.ReleaseMutex();
return memoryLocation;
});
}
catch (Exception)
{
minimumAddress += 0x10000;
}
}
_allocateMemoryMutex.ReleaseMutex();
throw allocationException;
}

/// <summary>
Expand Down

0 comments on commit 64ce6e1

Please sign in to comment.