From 96d4ad952c60e99c1d814ad7680106a5eabcb0d8 Mon Sep 17 00:00:00 2001 From: gdk Date: Thu, 23 Jun 2022 13:52:45 -0300 Subject: [PATCH] Fix reprotection regression --- .../WindowsShared/PlaceholderManager.cs | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs index 6db8d7df1c..f1752229bb 100644 --- a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs +++ b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs @@ -69,6 +69,11 @@ namespace Ryujinx.Memory.WindowsShared { _mappings.Add(new RangeNode(address, address + size, ulong.MaxValue)); } + + lock (_protections) + { + _protections.Add(new RangeNode(address, size, MemoryPermission.None)); + } } /// @@ -104,14 +109,6 @@ namespace Ryujinx.Memory.WindowsShared } } - if (count > 1) - { - CheckFreeResult(WindowsApi.VirtualFree( - (IntPtr)address, - (IntPtr)size, - AllocationType.Release | AllocationType.CoalescePlaceholders)); - } - RemoveProtection(address, size); } @@ -130,7 +127,7 @@ namespace Ryujinx.Memory.WindowsShared try { - UnmapViewInternal(sharedMemory, location, size, owner); + UnmapViewInternal(sharedMemory, location, size, owner, updateProtection: false); MapViewInternal(sharedMemory, srcOffset, location, size); } finally @@ -166,6 +163,8 @@ namespace Ryujinx.Memory.WindowsShared { throw new WindowsApiException("MapViewOfFile3"); } + + UpdateProtection((ulong)location, (ulong)size, MemoryPermission.ReadAndWrite); } /// @@ -189,7 +188,6 @@ namespace Ryujinx.Memory.WindowsShared var overlap = overlaps[0]; - // Tree operations might modify the node start/end values, so save a copy before we modify the tree. ulong overlapStart = overlap.Start; ulong overlapEnd = overlap.End; ulong overlapValue = overlap.Value; @@ -254,7 +252,7 @@ namespace Ryujinx.Memory.WindowsShared try { - UnmapViewInternal(sharedMemory, location, size, owner); + UnmapViewInternal(sharedMemory, location, size, owner, updateProtection: true); } finally { @@ -273,8 +271,9 @@ namespace Ryujinx.Memory.WindowsShared /// Address to unmap /// Size of the region to unmap in bytes /// Memory block that owns the mapping + /// Indicates if the memory protections should be updated after the unmap /// Thrown when the Windows API returns an error unmapping or remapping the memory - private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner) + private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner, bool updateProtection) { ulong startAddress = (ulong)location; ulong unmapSize = (ulong)size; @@ -294,7 +293,6 @@ namespace Ryujinx.Memory.WindowsShared if (IsMapped(overlap.Value)) { - // Tree operations might modify the node start/end values, so save a copy before we modify the tree. ulong overlapStart = overlap.Start; ulong overlapEnd = overlap.End; ulong overlapValue = overlap.Value; @@ -360,7 +358,11 @@ namespace Ryujinx.Memory.WindowsShared } CoalesceForUnmap(startAddress, unmapSize, owner); - RemoveProtection(startAddress, unmapSize); + + if (updateProtection) + { + UpdateProtection(startAddress, unmapSize, MemoryPermission.None); + } } /// @@ -512,19 +514,10 @@ namespace Ryujinx.Memory.WindowsShared success = false; } - - // We only keep track of "non-standard" protections, - // that is, everything that is not just RW (which is the default when views are mapped). - if (permission == MemoryPermission.ReadAndWrite) - { - RemoveProtection(mappedAddress, mappedSize); - } - else - { - AddProtection(mappedAddress, mappedSize, permission); - } } + UpdateProtection(reprotectAddress, reprotectSize, permission); + return success; } @@ -573,7 +566,7 @@ namespace Ryujinx.Memory.WindowsShared /// Address of the protected region /// Size of the protected region in bytes /// Memory permissions of the region - private void AddProtection(ulong address, ulong size, MemoryPermission permission) + private void UpdateProtection(ulong address, ulong size, MemoryPermission permission) { ulong endAddress = address + size; var overlaps = new RangeNode[InitialOverlapsSize]; @@ -693,6 +686,12 @@ namespace Ryujinx.Memory.WindowsShared { var protection = overlaps[index]; + // If protection is R/W we don't need to reprotect as views are initially mapped as R/W. + if (protection.Value == MemoryPermission.ReadAndWrite) + { + continue; + } + ulong protAddress = protection.Start; ulong protEndAddress = protection.End;