Rémi Bernon : ntdll: Replace incorrect find_free_reserved_area function call.

Alexandre Julliard julliard at winehq.org
Fri Dec 27 15:47:36 CST 2019


Module: wine
Branch: master
Commit: 1a44ef32379039f7d0d828d9d190aa94da02b1ee
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1a44ef32379039f7d0d828d9d190aa94da02b1ee

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Thu Dec 26 22:27:27 2019 +0100

ntdll: Replace incorrect find_free_reserved_area function call.

This introduces map_free_area function which tries mapping the expected
free areas until it finds one that succeeds. It now also works for
memory regions outside of the reserved region, but could probably be
improved.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/virtual.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 92 insertions(+), 5 deletions(-)

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 1fe173825d..953cf58901 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -535,6 +535,90 @@ static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end
 }
 
 
+/***********************************************************************
+ *           try_map_free_area
+ *
+ * Try mmaping some expected free memory region, eventually stepping and
+ * retrying inside it, and return where it actually succeeded, or NULL.
+ */
+static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
+                                void *start, size_t size, int unix_prot )
+{
+    void *ptr;
+
+    while (start && base <= start && (char*)start + size <= (char*)end)
+    {
+        if ((ptr = wine_anon_mmap( start, size, unix_prot, 0 )) == start)
+            return start;
+        TRACE( "Found free area is already mapped, start %p.\n", start );
+
+        if (ptr != (void *)-1)
+            munmap( ptr, size );
+
+        if ((step > 0 && (char *)end - (char *)start < step) ||
+            (step < 0 && (char *)start - (char *)base < -step) ||
+            step == 0)
+            break;
+        start = (char *)start + step;
+    }
+
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           map_free_area
+ *
+ * Find a free area between views inside the specified range and map it.
+ * The csVirtual section must be held by caller.
+ */
+static void *map_free_area( void *base, void *end, size_t size, size_t mask, int top_down,
+                             int unix_prot )
+{
+    struct wine_rb_entry *first = find_view_inside_range( &base, &end, top_down );
+    ptrdiff_t step = top_down ? -(mask + 1) : (mask + 1);
+    void *start;
+
+    if (top_down)
+    {
+        start = ROUND_ADDR( (char *)end - size, mask );
+        if (start >= end || start < base) return NULL;
+
+        while (first)
+        {
+            struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry );
+            if ((start = try_map_free_area( (char *)view->base + view->size, (char *)start + size, step,
+                                            start, size, unix_prot ))) break;
+            start = ROUND_ADDR( (char *)view->base - size, mask );
+            /* stop if remaining space is not large enough */
+            if (!start || start >= end || start < base) return NULL;
+            first = wine_rb_prev( first );
+        }
+    }
+    else
+    {
+        start = ROUND_ADDR( (char *)base + mask, mask );
+        if (!start || start >= end || (char *)end - (char *)start < size) return NULL;
+
+        while (first)
+        {
+            struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry );
+            if ((start = try_map_free_area( start, view->base, step,
+                                            start, size, unix_prot ))) break;
+            start = ROUND_ADDR( (char *)view->base + view->size + mask, mask );
+            /* stop if remaining space is not large enough */
+            if (!start || start >= end || (char *)end - (char *)start < size) return NULL;
+            first = wine_rb_next( first );
+        }
+    }
+
+    if (!first)
+        return try_map_free_area( base, end, step, start, size, unix_prot );
+
+    return start;
+}
+
+
 /***********************************************************************
  *           find_reserved_free_area
  *
@@ -1181,14 +1265,17 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
             goto done;
         }
 
-        for (;;)
+        if (zero_bits_64)
         {
-            if (!zero_bits_64)
-                ptr = NULL;
-            else if (!(ptr = find_reserved_free_area( (void*)0, alloc.limit, view_size, mask, top_down )))
+            if (!(ptr = map_free_area( (void*)0, alloc.limit, size, mask, top_down, VIRTUAL_GetUnixProt(vprot) )))
                 return STATUS_NO_MEMORY;
+            TRACE( "got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size );
+            goto done;
+        }
 
-            if ((ptr = wine_anon_mmap( ptr, view_size, VIRTUAL_GetUnixProt(vprot), ptr ? MAP_FIXED : 0 )) == (void *)-1)
+        for (;;)
+        {
+            if ((ptr = wine_anon_mmap( NULL, view_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
             {
                 if (errno == ENOMEM) return STATUS_NO_MEMORY;
                 return STATUS_INVALID_PARAMETER;




More information about the wine-cvs mailing list