From 8f0899a814e6d43c2be0c98f766ce76f1c25a0d4 Mon Sep 17 00:00:00 2001 From: marzent Date: Mon, 11 Apr 2022 09:19:10 +0200 Subject: [PATCH] make MemoryBufferHelper.Allocate more reliable (with wine) --- .../MemoryBufferHelper.cs | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Source/Reloaded.Memory.Buffers/MemoryBufferHelper.cs b/Source/Reloaded.Memory.Buffers/MemoryBufferHelper.cs index 5176af3..9fc452c 100644 --- a/Source/Reloaded.Memory.Buffers/MemoryBufferHelper.cs +++ b/Source/Reloaded.Memory.Buffers/MemoryBufferHelper.cs @@ -240,11 +240,12 @@ public MemoryBuffer[] FindBuffers(int size, IntPtr minimumAddress, IntPtr maximu /// The minimum size of the memory to be allocated. /// The minimum absolute address to allocate in. /// The maximum absolute address to allocate in. - /// In the case the memory allocation fails; the amount of times memory allocation is to be retried. + /// In the case the memory allocation for a potential location fails; the amount of times memory allocation is to be retried. /// Memory allocation failure due to possible race condition with other process/process itself/Windows scheduling. /// /// This function is virtually the same to running 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. /// public BufferAllocationProperties Allocate(int size, int minimumAddress = 0x10000, int maximumAddress = 0x7FFFFFFF, int retryCount = 3) @@ -252,30 +253,34 @@ public BufferAllocationProperties Allocate(int size, int minimumAddress = 0x1000 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; } ///