Akihiro Sagawa : ntdll: Allow map_view() to allocate fixed memory between reserved area and non-reserved area.

Alexandre Julliard julliard at winehq.org
Thu Jul 13 14:41:34 CDT 2017


Module: wine
Branch: master
Commit: 74b7fcfbdb87b4e0ca4d4a3193af52410da8d1b4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=74b7fcfbdb87b4e0ca4d4a3193af52410da8d1b4

Author: Akihiro Sagawa <sagawa.aki at gmail.com>
Date:   Mon Jul 10 22:21:32 2017 +0900

ntdll: Allow map_view() to allocate fixed memory between reserved area and non-reserved area.

Signed-off-by: Akihiro Sagawa <sagawa.aki at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/virtual.c | 155 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 120 insertions(+), 35 deletions(-)

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index ee9c8d0..4aeb282 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -404,6 +404,42 @@ static void remove_reserved_area( void *addr, size_t size )
 }
 
 
+struct area_boundary
+{
+    void  *base;
+    size_t size;
+    void  *boundary;
+};
+
+/***********************************************************************
+ *           get_area_boundary_callback
+ *
+ * Get lowest boundary address between reserved area and non-reserved area
+ * in the specified region. If no boundaries are found, result is NULL.
+ * The csVirtual section must be held by caller.
+ */
+static int get_area_boundary_callback( void *start, size_t size, void *arg )
+{
+    struct area_boundary *area = arg;
+    void *end = (char *)start + size;
+
+    area->boundary = NULL;
+    if (area->base >= end) return 0;
+    if ((char *)start >= (char *)area->base + area->size) return 1;
+    if (area->base >= start)
+    {
+        if ((char *)area->base + area->size > (char *)end)
+        {
+            area->boundary = end;
+            return 1;
+        }
+        return 0;
+    }
+    area->boundary = start;
+    return 1;
+}
+
+
 /***********************************************************************
  *           is_beyond_limit
  *
@@ -423,12 +459,32 @@ static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *l
  */
 static inline void unmap_area( void *addr, size_t size )
 {
-    if (wine_mmap_is_in_reserved_area( addr, size ))
+    switch (wine_mmap_is_in_reserved_area( addr, size ))
+    {
+    case -1: /* partially in a reserved area */
+    {
+        struct area_boundary area;
+        size_t lower_size;
+        area.base = addr;
+        area.size = size;
+        wine_mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 );
+        assert( area.boundary );
+        lower_size = (char *)area.boundary - (char *)addr;
+        unmap_area( addr, lower_size );
+        unmap_area( area.boundary, size - lower_size );
+        break;
+    }
+    case 1:  /* in a reserved area */
         wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED );
-    else if (is_beyond_limit( addr, size, user_space_limit ))
-        add_reserved_area( addr, size );
-    else
-        munmap( addr, size );
+        break;
+    default:
+    case 0:  /* not in a reserved area */
+        if (is_beyond_limit( addr, size, user_space_limit ))
+            add_reserved_area( addr, size );
+        else
+            munmap( addr, size );
+        break;
+    }
 }
 
 
@@ -773,6 +829,62 @@ static int alloc_reserved_area_callback( void *start, size_t size, void *arg )
     return 0;
 }
 
+/***********************************************************************
+ *           map_fixed_area
+ *
+ * mmap the fixed memory area.
+ * The csVirtual section must be held by caller.
+ */
+static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
+{
+    void *ptr;
+
+    switch (wine_mmap_is_in_reserved_area( base, size ))
+    {
+    case -1: /* partially in a reserved area */
+    {
+        NTSTATUS status;
+        struct area_boundary area;
+        size_t lower_size;
+        area.base = base;
+        area.size = size;
+        wine_mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 );
+        assert( area.boundary );
+        lower_size = (char *)area.boundary - (char *)base;
+        status = map_fixed_area( base, lower_size, vprot );
+        if (status == STATUS_SUCCESS)
+        {
+            status = map_fixed_area( area.boundary, size - lower_size, vprot);
+            if (status != STATUS_SUCCESS) unmap_area( base, lower_size );
+        }
+        return status;
+    }
+    case 0:  /* not in a reserved area, do a normal allocation */
+        if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
+        {
+            if (errno == ENOMEM) return STATUS_NO_MEMORY;
+            return STATUS_INVALID_PARAMETER;
+        }
+        if (ptr != base)
+        {
+            /* We couldn't get the address we wanted */
+            if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size );
+            else munmap( ptr, size );
+            return STATUS_CONFLICTING_ADDRESSES;
+        }
+        break;
+
+    default:
+    case 1:  /* in a reserved area, make sure the address is available */
+        if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
+        /* replace the reserved area by our mapping */
+        if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base)
+            return STATUS_INVALID_PARAMETER;
+        break;
+    }
+    if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
+    return STATUS_SUCCESS;
+}
 
 /***********************************************************************
  *           map_view
@@ -790,36 +902,9 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
     {
         if (is_beyond_limit( base, size, address_space_limit ))
             return STATUS_WORKING_SET_LIMIT_RANGE;
-
-        switch (wine_mmap_is_in_reserved_area( base, size ))
-        {
-        case -1: /* partially in a reserved area */
-            return STATUS_CONFLICTING_ADDRESSES;
-
-        case 0:  /* not in a reserved area, do a normal allocation */
-            if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
-            {
-                if (errno == ENOMEM) return STATUS_NO_MEMORY;
-                return STATUS_INVALID_PARAMETER;
-            }
-            if (ptr != base)
-            {
-                /* We couldn't get the address we wanted */
-                if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size );
-                else munmap( ptr, size );
-                return STATUS_CONFLICTING_ADDRESSES;
-            }
-            break;
-
-        default:
-        case 1:  /* in a reserved area, make sure the address is available */
-            if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
-            /* replace the reserved area by our mapping */
-            if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base)
-                return STATUS_INVALID_PARAMETER;
-            break;
-        }
-        if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
+        status = map_fixed_area( base, size, vprot );
+        if (status != STATUS_SUCCESS) return status;
+        ptr = base;
     }
     else
     {




More information about the wine-cvs mailing list