From eda2aae6a4845e3b0f5e4edb805fb4add4316f17 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Tue, 2 Jun 2020 21:06:33 +0300
Subject: [PATCH] ntdll: Permanently exclude natively mapped areas from free
 areas list.

---
 dlls/ntdll/unix/virtual.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 667401aaa93..c49c60166c2 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -124,6 +124,9 @@ static const BYTE VIRTUAL_Win32Flags[16] =
 static struct wine_rb_tree views_tree;
 static pthread_mutex_t virtual_mutex;
 
+static void *last_already_mapped;
+static size_t last_already_mapped_size;
+
 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
 static const UINT page_shift = 12;
 static const UINT_PTR page_mask = 0xfff;
@@ -997,6 +1000,13 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
         if (ptr != (void *)-1)
             munmap( ptr, size );
 
+        if (!last_already_mapped && step)
+        {
+            last_already_mapped = start;
+            last_already_mapped_size = step > 0 ? step : -step;
+            last_already_mapped_size = min(last_already_mapped_size, (char *)end - (char *)start);
+        }
+
         if ((step > 0 && (char *)end - (char *)start < step) ||
             (step < 0 && (char *)start - (char *)base < -step) ||
             step == 0)
@@ -1841,9 +1851,24 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
 
         if (is_win64 || zero_bits_64)
         {
+            last_already_mapped = NULL;
+
             if (!(ptr = alloc_free_area( alloc.limit, alloc.size, top_down, alloc.unix_prot)))
                 return STATUS_NO_MEMORY;
 
+            if (last_already_mapped)
+            {
+                void *last_mapped_start, *last_mapped_end;
+
+                TRACE("Permanently excluding %p - %p from free list.\n",
+                        last_already_mapped, (char *)last_already_mapped + last_already_mapped_size - 1);
+                last_mapped_start = ROUND_ADDR(last_already_mapped, granularity_mask);
+                last_mapped_end = ROUND_ADDR((char *)last_already_mapped + last_already_mapped_size + granularity_mask,
+                        granularity_mask);
+                if (ptr > last_mapped_end || (char *)ptr + size < (char *)last_mapped_start)
+                    free_ranges_remove_range(last_mapped_start, last_mapped_end, last_already_mapped);
+            }
+
             TRACE( "got mem in free area %p-%p\n", ptr, (char *)ptr + size );
             goto done;
         }
-- 
2.27.0

