Updated and re-enabled ntdll-ForceBottomUpAlloc patchset.

This commit is contained in:
Paul Gofman 2022-11-12 18:30:04 -06:00 committed by Alistair Leslie-Hughes
parent 1a2b47b084
commit 31acabe792
6 changed files with 295 additions and 236 deletions

View File

@ -1,4 +1,4 @@
From d28a26a59e9837191cc48854d5dad16eba532f04 Mon Sep 17 00:00:00 2001
From 5814a4b9c7d4dec027b0c2dd29822664aa56ada1 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Tue, 14 Jan 2020 21:39:23 +0300
Subject: [PATCH] ntdll: Increase step after failed map attempt in
@ -9,10 +9,10 @@ Subject: [PATCH] ntdll: Increase step after failed map attempt in
1 file changed, 1 insertion(+)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index d79e3de662e..f8f317a6483 100644
index 84a4e331ad7..a63882023e6 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -1073,6 +1073,7 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
@@ -1327,6 +1327,7 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
step == 0)
break;
start = (char *)start + step;
@ -21,5 +21,5 @@ index d79e3de662e..f8f317a6483 100644
return NULL;
--
2.26.2
2.38.1

View File

@ -1,4 +1,4 @@
From 266f5082387ec92cb79a2ec3ce71d956cf05190d Mon Sep 17 00:00:00 2001
From b1e6d32e7dc3bac93419f3a573f509ee6e1177b2 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 23 Jul 2020 18:40:39 +0300
Subject: [PATCH] ntdll: Increase free ranges view block size on 64 bit.
@ -8,10 +8,10 @@ Subject: [PATCH] ntdll: Increase free ranges view block size on 64 bit.
1 file changed, 4 insertions(+)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index f8f317a6483..4ca033b0e19 100644
index a63882023e6..83909f57d4a 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -183,7 +183,11 @@ static BYTE *pages_vprot;
@@ -205,7 +205,11 @@ static BYTE *pages_vprot;
#endif
static struct file_view *view_block_start, *view_block_end, *next_free_view;
@ -24,5 +24,5 @@ index f8f317a6483..4ca033b0e19 100644
static void *preload_reserve_end;
static BOOL force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mmaps */
--
2.26.2
2.38.1

View File

@ -1,28 +1,29 @@
From 0cb1d81c14522afe45b1bb5a8194efd2470efe27 Mon Sep 17 00:00:00 2001
From c3252fd68ecdcc0186b4d284df1b36ea11ca7d7f Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Mon, 25 Nov 2019 12:19:20 +0300
Subject: [PATCH] ntdll: Force virtual memory allocation order.
Windows allocates virtual memory strictly bottom up or
top down depending on the requested flags. Modern Linux
VM allocator always allocates memory top down. Some
top down depending on the requested flags (when ASLR is disabled).
Modern Linux VM allocator always allocates memory top down. Some
applications break if the allocated memory addresses
are from higher memory than they expect.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48175
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46568
---
dlls/ntdll/unix/virtual.c | 417 ++++++++++++++++++--------------------
1 file changed, 202 insertions(+), 215 deletions(-)
dlls/ntdll/unix/virtual.c | 450 +++++++++++++++++++-------------------
1 file changed, 227 insertions(+), 223 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 7654055f59b..e971e0523ba 100644
index 83909f57d4a..4bce8f2f806 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -1202,44 +1202,6 @@ static struct file_view *find_view_range( const void *addr, size_t size )
@@ -1266,44 +1266,15 @@ static struct file_view *find_view_range( const void *addr, size_t size )
return NULL;
}
-
-/***********************************************************************
- * find_view_inside_range
- *
@ -30,7 +31,8 @@ index 7654055f59b..e971e0523ba 100644
- * virtual_mutex must be held by caller.
- */
-static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end_ptr, int top_down )
-{
+struct alloc_area
{
- struct wine_rb_entry *first = NULL, *ptr = views_tree.root;
- void *base = *base_ptr, *end = *end_ptr;
-
@ -60,11 +62,17 @@ index 7654055f59b..e971e0523ba 100644
- return first;
-}
-
-
+ char *map_area_start, *map_area_end, *result;
+ size_t size;
+ ptrdiff_t step;
+ int unix_prot;
+ BOOL top_down;
+ UINT_PTR align_mask;
+};
/***********************************************************************
* try_map_free_area
*
@@ -1272,110 +1234,6 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
@@ -1337,110 +1308,6 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
return NULL;
}
@ -75,15 +83,15 @@ index 7654055f59b..e971e0523ba 100644
- * Find a free area between views inside the specified range and map it.
- * virtual_mutex must be held by caller.
- */
-static void *map_free_area( void *base, void *end, size_t size, int top_down, int unix_prot )
-static void *map_free_area( void *base, void *end, size_t size, int top_down, int unix_prot, size_t align_mask )
-{
- struct wine_rb_entry *first = find_view_inside_range( &base, &end, top_down );
- ptrdiff_t step = top_down ? -(granularity_mask + 1) : (granularity_mask + 1);
- ptrdiff_t step = top_down ? -(align_mask + 1) : (align_mask + 1);
- void *start;
-
- if (top_down)
- {
- start = ROUND_ADDR( (char *)end - size, granularity_mask );
- start = ROUND_ADDR( (char *)end - size, align_mask );
- if (start >= end || start < base) return NULL;
-
- while (first)
@ -91,7 +99,7 @@ index 7654055f59b..e971e0523ba 100644
- 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, granularity_mask );
- start = ROUND_ADDR( (char *)view->base - size, align_mask );
- /* stop if remaining space is not large enough */
- if (!start || start >= end || start < base) return NULL;
- first = rb_prev( first );
@ -99,7 +107,7 @@ index 7654055f59b..e971e0523ba 100644
- }
- else
- {
- start = ROUND_ADDR( (char *)base + granularity_mask, granularity_mask );
- start = ROUND_ADDR( (char *)base + align_mask, align_mask );
- if (!start || start >= end || (char *)end - (char *)start < size) return NULL;
-
- while (first)
@ -107,7 +115,7 @@ index 7654055f59b..e971e0523ba 100644
- 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 + granularity_mask, granularity_mask );
- start = ROUND_ADDR( (char *)view->base + view->size + align_mask, align_mask );
- /* stop if remaining space is not large enough */
- if (!start || start >= end || (char *)end - (char *)start < size) return NULL;
- first = rb_next( first );
@ -128,13 +136,13 @@ index 7654055f59b..e971e0523ba 100644
- * virtual_mutex must be held by caller.
- * The range must be inside the preloader reserved range.
- */
-static void *find_reserved_free_area( void *base, void *end, size_t size, int top_down )
-static void *find_reserved_free_area( void *base, void *end, size_t size, int top_down, size_t align_mask )
-{
- struct range_entry *range;
- void *start;
-
- base = ROUND_ADDR( (char *)base + granularity_mask, granularity_mask );
- end = (char *)ROUND_ADDR( (char *)end - size, granularity_mask ) + size;
- base = ROUND_ADDR( (char *)base + align_mask, align_mask );
- end = (char *)ROUND_ADDR( (char *)end - size, align_mask ) + size;
-
- if (top_down)
- {
@ -142,13 +150,13 @@ index 7654055f59b..e971e0523ba 100644
- range = free_ranges_lower_bound( start );
- assert(range != free_ranges_end && range->end >= start);
-
- if ((char *)range->end - (char *)start < size) start = ROUND_ADDR( (char *)range->end - size, granularity_mask );
- if ((char *)range->end - (char *)start < size) start = ROUND_ADDR( (char *)range->end - size, align_mask );
- do
- {
- if (start >= end || start < base || (char *)end - (char *)start < size) return NULL;
- if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break;
- if (--range < free_ranges) return NULL;
- start = ROUND_ADDR( (char *)range->end - size, granularity_mask );
- start = ROUND_ADDR( (char *)range->end - size, align_mask );
- }
- while (1);
- }
@ -158,13 +166,13 @@ index 7654055f59b..e971e0523ba 100644
- range = free_ranges_lower_bound( start );
- assert(range != free_ranges_end && range->end >= start);
-
- if (start < range->base) start = ROUND_ADDR( (char *)range->base + granularity_mask, granularity_mask );
- if (start < range->base) start = ROUND_ADDR( (char *)range->base + align_mask, align_mask );
- do
- {
- if (start >= end || start < base || (char *)end - (char *)start < size) return NULL;
- if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break;
- if (++range == free_ranges_end) return NULL;
- start = ROUND_ADDR( (char *)range->base + granularity_mask, granularity_mask );
- start = ROUND_ADDR( (char *)range->base + align_mask, align_mask );
- }
- while (1);
- }
@ -175,39 +183,45 @@ index 7654055f59b..e971e0523ba 100644
/***********************************************************************
* add_reserved_area
*
@@ -1533,8 +1391,7 @@ static void delete_view( struct file_view *view ) /* [in] View */
@@ -1608,8 +1475,7 @@ static void free_view( struct file_view *view )
*/
static void unregister_view( struct file_view *view )
{
if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size );
set_page_vprot( view->base, view->size, 0 );
- if (mmap_is_in_reserved_area( view->base, view->size ))
- free_ranges_remove_view( view );
+ free_ranges_remove_view( view );
wine_rb_remove( &views_tree, &view->entry );
*(struct file_view **)view = next_free_view;
next_free_view = view;
@@ -1582,8 +1439,7 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz
set_page_vprot( base, size, vprot );
}
@@ -1636,8 +1502,7 @@ static void delete_view( struct file_view *view ) /* [in] View */
static void register_view( struct file_view *view )
{
wine_rb_put( &views_tree, view->base, &view->entry );
- if (mmap_is_in_reserved_area( view->base, view->size ))
- free_ranges_insert_view( view );
+ free_ranges_insert_view( view );
}
*view_ret = view;
@@ -1797,51 +1653,218 @@ static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t want
@@ -1906,55 +1771,229 @@ static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t want
return ptr;
}
struct alloc_area
-
-struct alloc_area
+static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, void *arg )
{
+ char *map_area_start, *map_area_end, *result;
size_t size;
- size_t size;
- int top_down;
- void *limit;
- void *result;
+ ptrdiff_t step;
+ int unix_prot;
+ BOOL top_down;
};
- size_t align_mask;
-};
+ char *intersect_start, *intersect_end;
+ char *end = (char *)start + size;
+ struct alloc_area *area = arg;
+ UINT_PTR align_mask;
+ char *alloc_start;
-/***********************************************************************
- * alloc_reserved_area_callback
@ -215,43 +229,77 @@ index 7654055f59b..e971e0523ba 100644
- * Try to map some space inside a reserved area. Callback for mmap_enum_reserved_areas.
- */
-static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg )
+static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, void *arg )
{
-{
- struct alloc_area *alloc = arg;
- void *end = (char *)start + size;
-
- if (start < address_space_start) start = address_space_start;
- if (is_beyond_limit( start, size, alloc->limit )) end = alloc->limit;
- if (start >= end) return 0;
+ char *intersect_start, *intersect_end;
+ char *end = (char *)start + size;
+ struct alloc_area *area = arg;
+ char *alloc_start;
- /* make sure we don't touch the preloader reserved range */
- if (preload_reserve_end >= start)
+ align_mask = area->align_mask;
+
+ if (area->top_down)
{
- if (preload_reserve_end >= end)
+ {
+ if (area->map_area_start >= end)
+ return 1;
+
+ if (area->map_area_end <= (char *)start)
+ return 0;
+
+ if ((ULONG_PTR)area->map_area_end < area->size)
+ return 1;
+
+ intersect_start = max((char *)start, area->map_area_start);
+ intersect_end = min((char *)end, area->map_area_end);
+
+ assert(ROUND_ADDR(intersect_start, granularity_mask) == intersect_start);
+ assert(ROUND_ADDR(intersect_end + granularity_mask, granularity_mask) == intersect_end);
+ assert(ROUND_ADDR(area->map_area_end, granularity_mask) == area->map_area_end);
+
+ assert(intersect_start <= intersect_end);
+ if (area->map_area_end - intersect_end >= area->size)
+ {
+ alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, align_mask );
+ if ((area->result = try_map_free_area( intersect_end, alloc_start + size, area->step,
+ alloc_start, area->size, area->unix_prot )))
+ return 1;
+ }
- if (start < address_space_start) start = address_space_start;
- if (is_beyond_limit( start, size, alloc->limit )) end = alloc->limit;
- if (start >= end) return 0;
+ if (intersect_end - intersect_start >= area->size)
+ {
+ alloc_start = ROUND_ADDR( intersect_end - area->size, align_mask );
+ if (alloc_start >= intersect_start)
+ {
+ if ((area->result = anon_mmap_fixed( alloc_start, area->size,
+ area->unix_prot, 0 )) != alloc_start)
+ ERR("Could not map in reserved area, alloc_start %p, size %p.\n",
+ alloc_start, (void *)area->size);
+ return 1;
+ }
+ }
- /* make sure we don't touch the preloader reserved range */
- if (preload_reserve_end >= start)
+ area->map_area_end = intersect_start;
+ if (area->map_area_end - area->map_area_start < area->size)
+ return 1;
+ }
+ else
{
- if (preload_reserve_end >= end)
+ if (area->map_area_end <= (char *)start)
+ return 1;
+
+ if (area->map_area_start >= (char *)end)
+ return 0;
+
+ if (area->map_area_start + align_mask < area->map_area_start)
+ return 1;
+
+ intersect_start = max((char *)start, area->map_area_start);
+ intersect_end = min((char *)end, area->map_area_end);
+ assert(intersect_start <= intersect_end);
+
+ if (intersect_start - area->map_area_start >= area->size)
{
- if (preload_reserve_start <= start) return 0; /* no space in that area */
- if (preload_reserve_start < end) end = preload_reserve_start;
+ alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, granularity_mask );
+ if ((area->result = try_map_free_area( intersect_end, alloc_start + size, area->step,
+ alloc_start = ROUND_ADDR( area->map_area_start + align_mask, align_mask );
+ if ((area->result = try_map_free_area( area->map_area_start, intersect_start, area->step,
+ alloc_start, area->size, area->unix_prot )))
+ return 1;
}
@ -262,55 +310,22 @@ index 7654055f59b..e971e0523ba 100644
{
- /* range is split in two by the preloader reservation, try first part */
- if ((alloc->result = find_reserved_free_area( start, preload_reserve_start, alloc->size,
- alloc->top_down )))
+ alloc_start = ROUND_ADDR( intersect_end - area->size, granularity_mask );
+ if ((area->result = anon_mmap_fixed( alloc_start, area->size,
+ area->unix_prot, 0 )) != alloc_start)
+ ERR("Could not map in reserved area, alloc_start %p, size %p.\n",
+ alloc_start, (void *)area->size);
+ return 1;
+ }
+
+ area->map_area_end = intersect_start;
+ if (area->map_area_end - area->map_area_start < area->size)
+ return 1;
+ }
+ else
+ {
+ if (area->map_area_end <= (char *)start)
+ return 1;
+
+ if (area->map_area_start >= (char *)end)
+ return 0;
+
+ intersect_start = max((char *)start, area->map_area_start);
+ intersect_end = min((char *)end, area->map_area_end);
+
+ assert(ROUND_ADDR(intersect_start, granularity_mask) == intersect_start);
+ assert(ROUND_ADDR(intersect_end + granularity_mask, granularity_mask) == intersect_end);
+ assert(ROUND_ADDR(area->map_area_start, granularity_mask) == area->map_area_start);
+
+ if (intersect_start - area->map_area_start >= area->size)
+ {
+ if ((area->result = try_map_free_area( area->map_area_start, intersect_start, area->step,
+ area->map_area_start, area->size, area->unix_prot )))
- alloc->top_down, alloc->align_mask )))
+ alloc_start = ROUND_ADDR( intersect_start + align_mask, align_mask );
+ if (alloc_start + area->size <= intersect_end)
+ {
+ if ((area->result = anon_mmap_fixed( alloc_start, area->size, area->unix_prot, 0 )) != alloc_start)
+ ERR("Could not map in reserved area, alloc_start %p, size %p.\n", alloc_start, (void *)area->size);
return 1;
- /* then fall through to try second part */
- start = preload_reserve_end;
+ }
}
+
+ if (intersect_end - intersect_start >= area->size)
+ {
+ if ((area->result = anon_mmap_fixed( intersect_start, area->size, area->unix_prot, 0 ))
+ != intersect_start)
+ ERR("Could not map in reserved area.\n");
+ return 1;
+ }
+ area->map_area_start = intersect_end;
+ if (area->map_area_end - area->map_area_start < area->size)
+ return 1;
}
- if ((alloc->result = find_reserved_free_area( start, end, alloc->size, alloc->top_down )))
- if ((alloc->result = find_reserved_free_area( start, end, alloc->size, alloc->top_down, alloc->align_mask )))
- return 1;
return 0;
@ -318,6 +333,7 @@ index 7654055f59b..e971e0523ba 100644
+static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char *end )
+{
+ UINT_PTR align_mask = area->align_mask;
+ char *start;
+
+ TRACE("range %p-%p.\n", base, end);
@ -330,13 +346,14 @@ index 7654055f59b..e971e0523ba 100644
+
+ if (area->top_down)
+ {
+ start = ROUND_ADDR( end - area->size, granularity_mask );
+ if (start >= end || start < base)
+ return NULL;
+ if ((ULONG_PTR)end < area->size) return NULL;
+ start = ROUND_ADDR( end - area->size, align_mask );
+ if (start >= end || start < base) return NULL;
+ }
+ else
+ {
+ start = ROUND_ADDR( base + granularity_mask, granularity_mask );
+ if (base + align_mask < base) return NULL;
+ start = ROUND_ADDR( base + align_mask, align_mask );
+ if (!start || start >= end || (char *)end - (char *)start < area->size)
+ return NULL;
+ }
@ -348,7 +365,8 @@ index 7654055f59b..e971e0523ba 100644
+
+ if (area->top_down)
+ {
+ start = ROUND_ADDR( area->map_area_end - area->size, granularity_mask );
+ if ((ULONG_PTR)area->map_area_end < area->size) return NULL;
+ start = ROUND_ADDR( area->map_area_end - area->size, align_mask );
+ if (start >= area->map_area_end || start < area->map_area_start)
+ return NULL;
+
@ -357,7 +375,8 @@ index 7654055f59b..e971e0523ba 100644
+ }
+ else
+ {
+ start = ROUND_ADDR( area->map_area_start + granularity_mask, granularity_mask );
+ if (area->map_area_start + align_mask < area->map_area_start) return NULL;
+ start = ROUND_ADDR( area->map_area_start + align_mask, align_mask );
+ if (!start || start >= area->map_area_end
+ || area->map_area_end - start < area->size)
+ return NULL;
@ -367,7 +386,7 @@ index 7654055f59b..e971e0523ba 100644
+ }
+}
+
+static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_prot )
+static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_prot, UINT_PTR align_mask )
+{
+ struct range_entry *range, *ranges_start, *ranges_end;
+ char *reserve_start, *reserve_end;
@ -391,13 +410,14 @@ index 7654055f59b..e971e0523ba 100644
+ }
+
+ memset( &area, 0, sizeof(area) );
+ area.step = top_down ? -(granularity_mask + 1) : (granularity_mask + 1);
+ area.step = top_down ? -(align_mask + 1) : (align_mask + 1);
+ area.size = size;
+ area.top_down = top_down;
+ area.unix_prot = unix_prot;
+ area.align_mask = align_mask;
+
+ reserve_start = ROUND_ADDR( (char *)preload_reserve_start, granularity_mask );
+ reserve_end = ROUND_ADDR( (char *)preload_reserve_end + granularity_mask, granularity_mask );
+ reserve_start = preload_reserve_start;
+ reserve_end = preload_reserve_end;
+
+ for (range = ranges_start; range != ranges_end; range += ranges_inc)
+ {
@ -406,10 +426,13 @@ index 7654055f59b..e971e0523ba 100644
+
+ TRACE("range %p-%p.\n", base, end);
+
+ if (base >= (char *)limit)
+ continue;
+
+ if (base < (char *)address_space_start)
+ base = (char *)address_space_start;
+ if (end > (char *)ROUND_ADDR( limit, granularity_mask ))
+ end = ROUND_ADDR( limit, granularity_mask );
+ if (end > (char *)limit)
+ end = (char *)limit;
+
+ if (reserve_end >= base)
+ {
@ -417,6 +440,7 @@ index 7654055f59b..e971e0523ba 100644
+ {
+ if (reserve_start <= base)
+ continue; /* no space in that area */
+
+ if (reserve_start < end)
+ end = reserve_start;
+ }
@ -428,14 +452,14 @@ index 7654055f59b..e971e0523ba 100644
+ {
+ /* range is split in two by the preloader reservation, try first part. */
+ if ((area.result = alloc_free_area_in_range( &area, base, reserve_start )))
+ return area.result;
+ break;
+ /* then fall through to try second part. */
+ base = reserve_end;
+ }
+ }
+
+ if ((area.result = alloc_free_area_in_range( &area, base, end )))
+ return area.result;
+ break;
+ }
+ return NULL;
+}
@ -443,20 +467,41 @@ index 7654055f59b..e971e0523ba 100644
/***********************************************************************
* map_fixed_area
*
@@ -1913,48 +1936,11 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
@@ -2019,6 +2058,8 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
void *ptr;
NTSTATUS status;
+ limit = limit ? min( limit + 1, (UINT_PTR)user_space_limit) : (UINT_PTR)user_space_limit;
+
if (alloc_type & MEM_REPLACE_PLACEHOLDER)
{
if ((*view_ret = find_view( base, 0 )))
@@ -2044,6 +2085,8 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
return STATUS_INVALID_PARAMETER;
}
+ if (!align_mask) align_mask = granularity_mask;
+
if (base)
{
if (is_beyond_limit( base, size, address_space_limit ))
@@ -2052,52 +2095,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
if (status != STATUS_SUCCESS) return status;
ptr = base;
}
- else
+ else if (!(ptr = alloc_free_area( (void*)(get_zero_bits_mask( zero_bits )
+ & (UINT_PTR)user_space_limit), size, top_down, get_unix_prot( vprot ) )))
+ else if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask )))
{
- size_t view_size = size + granularity_mask + 1;
- struct alloc_area alloc;
- size_t view_size;
-
- if (!align_mask) align_mask = granularity_mask;
- view_size = size + align_mask + 1;
-
- alloc.size = size;
- alloc.top_down = top_down;
- alloc.limit = (void*)(get_zero_bits_mask( zero_bits ) & (UINT_PTR)user_space_limit);
- alloc.limit = limit ? min( (void *)(limit + 1), user_space_limit ) : user_space_limit;
- alloc.align_mask = align_mask;
-
- if (mmap_enum_reserved_areas( alloc_reserved_area_callback, &alloc, top_down ))
- {
@ -467,10 +512,10 @@ index 7654055f59b..e971e0523ba 100644
- goto done;
- }
-
- if (zero_bits)
- if (limit)
- {
- if (!(ptr = map_free_area( address_space_start, alloc.limit, size,
- top_down, get_unix_prot(vprot) )))
- top_down, get_unix_prot(vprot), align_mask )))
- return STATUS_NO_MEMORY;
- TRACE( "got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size );
- goto done;
@ -488,14 +533,22 @@ index 7654055f59b..e971e0523ba 100644
- if (is_beyond_limit( ptr, view_size, user_space_limit )) add_reserved_area( ptr, view_size );
- else break;
- }
- ptr = unmap_extra_space( ptr, view_size, size );
- ptr = unmap_extra_space( ptr, view_size, size, align_mask );
+ return STATUS_NO_MEMORY;
}
-done:
status = create_view( view_ret, ptr, size, vprot );
if (status != STATUS_SUCCESS) unmap_area( ptr, size );
return status;
@@ -2680,6 +2666,7 @@ void virtual_init(void)
@@ -2758,6 +2759,7 @@ static NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_PTR z
done:
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
if (needs_close) close( unix_handle );
+ TRACE("status %#x.\n", res);
return res;
}
@@ -2826,6 +2828,7 @@ void virtual_init(void)
if (preload_reserve_start)
address_space_start = min( address_space_start, preload_reserve_start );
}
@ -503,6 +556,14 @@ index 7654055f59b..e971e0523ba 100644
}
/* try to find space in a reserved area for the views and pages protection table */
@@ -5579,6 +5582,7 @@ NTSTATUS WINAPI NtWow64AllocateVirtualMemory64( HANDLE process, ULONG64 *ret, UL
*ret = (ULONG_PTR)base;
*size_ptr = size;
}
+ TRACE("status %#x.\n", status);
return status;
}
--
2.34.1
2.38.1

View File

@ -1,25 +1,25 @@
From bcc882f5d1980cbf353891d1e1686e97c068f8c7 Mon Sep 17 00:00:00 2001
From d29a79d8cca2220c838fbbea6ea81b9f73070ba5 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: Exclude natively mapped areas from free areas list.
---
dlls/ntdll/unix/virtual.c | 137 ++++++++++++++++++++++++++++++--------
1 file changed, 109 insertions(+), 28 deletions(-)
dlls/ntdll/unix/virtual.c | 118 ++++++++++++++++++++++++++++++++------
1 file changed, 100 insertions(+), 18 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 4899fc7b443..cee739bd942 100644
index 4bce8f2f806..3c1bf6edc30 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -143,6 +143,7 @@ struct file_view
#define VPROT_WRITEWATCH 0x40
/* per-mapping protection flags */
@@ -125,6 +125,7 @@ struct file_view
#define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */
+#define VPROT_NATIVE 0x0400
#define VPROT_PLACEHOLDER 0x0400
#define VPROT_FROMPLACEHOLDER 0x0800
+#define VPROT_NATIVE 0x1000
/* Conversion from VPROT_* to Win32 flags */
static const BYTE VIRTUAL_Win32Flags[16] =
@@ -1081,7 +1082,9 @@ static void dump_view( struct file_view *view )
@@ -1119,7 +1120,9 @@ static void dump_view( struct file_view *view )
BYTE prot = get_page_vprot( addr );
TRACE( "View: %p - %p", addr, addr + view->size - 1 );
@ -28,26 +28,18 @@ index 4899fc7b443..cee739bd942 100644
+ TRACE(" (native)\n");
+ else if (view->protect & VPROT_SYSTEM)
TRACE( " (builtin image)\n" );
else if (view->protect & SEC_IMAGE)
TRACE( " (image)\n" );
@@ -1216,6 +1219,16 @@ static struct file_view *find_view_range( const void *addr, size_t size )
return NULL;
}
+struct alloc_area
+{
+ char *map_area_start, *map_area_end, *result;
+ size_t size;
+ ptrdiff_t step;
+ int unix_prot;
+ BOOL top_down;
else if (view->protect & VPROT_PLACEHOLDER)
TRACE( " (placeholder)\n" );
@@ -1274,6 +1277,8 @@ struct alloc_area
int unix_prot;
BOOL top_down;
UINT_PTR align_mask;
+ char *native_mapped;
+ size_t native_mapped_size;
+};
};
/***********************************************************************
* try_map_free_area
@@ -1223,21 +1236,27 @@ static struct file_view *find_view_range( const void *addr, size_t size )
@@ -1282,21 +1287,28 @@ struct alloc_area
* Try mmaping some expected free memory region, eventually stepping and
* retrying inside it, and return where it actually succeeded, or NULL.
*/
@ -56,6 +48,7 @@ index 4899fc7b443..cee739bd942 100644
+static void* try_map_free_area( struct alloc_area *area, void *base, void *end, void *start )
{
+ ptrdiff_t step = area->step;
+ UINT_PTR abs_step = step > 0 ? step : -step;
void *ptr;
- while (start && base <= start && (char*)start + size <= (char*)end)
@ -71,54 +64,40 @@ index 4899fc7b443..cee739bd942 100644
+ strerror(errno), start, (char *)start + area->size, area->unix_prot );
return NULL;
}
+ if (!area->native_mapped && step)
+ if (!area->native_mapped && step && abs_step < (granularity_mask + 1) * 2)
+ {
+ area->native_mapped = start;
+ area->native_mapped_size = step > 0 ? step : -step;
+ area->native_mapped_size = abs_step;
+ area->native_mapped_size = min(area->native_mapped_size, (char *)end - (char *)start);
+ }
if ((step > 0 && (char *)end - (char *)start < step) ||
(step < 0 && (char *)start - (char *)base < -step) ||
step == 0)
@@ -1666,15 +1685,6 @@ static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t want
}
-struct alloc_area
-{
- char *map_area_start, *map_area_end, *result;
- size_t size;
- ptrdiff_t step;
- int unix_prot;
- BOOL top_down;
-};
-
static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, void *arg )
{
char *intersect_start, *intersect_end;
@@ -1700,8 +1710,8 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size,
@@ -1797,9 +1809,9 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size,
assert(intersect_start <= intersect_end);
if (area->map_area_end - intersect_end >= area->size)
{
alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, granularity_mask );
- alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, align_mask );
- if ((area->result = try_map_free_area( intersect_end, alloc_start + size, area->step,
- alloc_start, area->size, area->unix_prot )))
+ alloc_start = ROUND_ADDR( (char *)area->map_area_end - area->size, align_mask );
+ if ((area->result = try_map_free_area( area, intersect_end,
+ alloc_start + size, alloc_start )))
return 1;
}
@@ -1736,8 +1746,8 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size,
@@ -1838,8 +1850,8 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size,
if (intersect_start - area->map_area_start >= area->size)
{
alloc_start = ROUND_ADDR( area->map_area_start + align_mask, align_mask );
- if ((area->result = try_map_free_area( area->map_area_start, intersect_start, area->step,
- area->map_area_start, area->size, area->unix_prot )))
- alloc_start, area->size, area->unix_prot )))
+ if ((area->result = try_map_free_area( area, area->map_area_start,
+ intersect_start, area->map_area_start )))
+ intersect_start, alloc_start )))
return 1;
}
@@ -1792,8 +1802,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char
@@ -1900,8 +1912,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char
if (start >= area->map_area_end || start < area->map_area_start)
return NULL;
@ -128,7 +107,7 @@ index 4899fc7b443..cee739bd942 100644
}
else
{
@@ -1802,8 +1811,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char
@@ -1911,8 +1922,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char
|| area->map_area_end - start < area->size)
return NULL;
@ -138,7 +117,7 @@ index 4899fc7b443..cee739bd942 100644
}
}
@@ -1813,6 +1821,7 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_
@@ -1922,6 +1932,7 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_
char *reserve_start, *reserve_end;
struct alloc_area area;
char *base, *end;
@ -146,20 +125,9 @@ index 4899fc7b443..cee739bd942 100644
int ranges_inc;
TRACE("limit %p, size %p, top_down %#x.\n", limit, (void *)size, top_down);
@@ -1868,16 +1877,67 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_
{
/* range is split in two by the preloader reservation, try first part. */
if ((area.result = alloc_free_area_in_range( &area, base, reserve_start )))
- return area.result;
+ break;
/* then fall through to try second part. */
base = reserve_end;
}
}
@@ -1991,7 +2002,58 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_
if ((area.result = alloc_free_area_in_range( &area, base, end )))
- return area.result;
+ break;
break;
}
- return NULL;
+
@ -217,7 +185,7 @@ index 4899fc7b443..cee739bd942 100644
}
/***********************************************************************
@@ -1931,6 +1991,17 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
@@ -2045,6 +2107,17 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
return STATUS_SUCCESS;
}
@ -235,21 +203,20 @@ index 4899fc7b443..cee739bd942 100644
/***********************************************************************
* map_view
*
@@ -1954,7 +2025,12 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
else if (!(ptr = alloc_free_area( (void*)(get_zero_bits_mask( zero_bits )
& (UINT_PTR)user_space_limit), size, top_down, get_unix_prot( vprot ) )))
@@ -2097,7 +2170,11 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
}
else if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask )))
{
- return STATUS_NO_MEMORY;
+ WARN("Allocation failed, clearing native views.\n");
+
+ clear_native_views();
+ if (!(ptr = alloc_free_area( (void*)(get_zero_bits_mask( zero_bits )
+ & (UINT_PTR)user_space_limit), size, top_down, get_unix_prot( vprot ) )))
+ if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask )))
+ return STATUS_NO_MEMORY;
}
status = create_view( view_ret, ptr, size, vprot );
if (status != STATUS_SUCCESS) unmap_area( ptr, size );
@@ -3646,7 +3722,12 @@ void virtual_set_force_exec( BOOL enable )
@@ -3835,7 +3912,12 @@ void virtual_set_force_exec( BOOL enable )
WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry )
{
/* file mappings are always accessible */
@ -264,5 +231,5 @@ index 4899fc7b443..cee739bd942 100644
mprotect_range( view->base, view->size, commit, 0 );
}
--
2.30.2
2.38.1

View File

@ -1,3 +1,3 @@
Fixes: [48175] AION (64 bit) - crashes in crysystem.dll.CryFree() due to high memory pointers allocated
Fixes: [46568] 64-bit msxml6.dll from Microsoft Core XML Services 6.0 redist package fails to load (Wine doesn't respect 44-bit user-mode VA limitation from Windows < 8.1)
Disabled: True
Depends: ntdll-Placeholders

View File

@ -133,6 +133,7 @@ patch_enable_all ()
enable_ntdll_Builtin_Prot="$1"
enable_ntdll_CriticalSection="$1"
enable_ntdll_Exception="$1"
enable_ntdll_ForceBottomUpAlloc="$1"
enable_ntdll_HashLinks="$1"
enable_ntdll_Hide_Wine_Exports="$1"
enable_ntdll_Junction_Points="$1"
@ -413,6 +414,9 @@ patch_enable ()
ntdll-Exception)
enable_ntdll_Exception="$2"
;;
ntdll-ForceBottomUpAlloc)
enable_ntdll_ForceBottomUpAlloc="$2"
;;
ntdll-HashLinks)
enable_ntdll_HashLinks="$2"
;;
@ -1225,6 +1229,13 @@ if test "$enable_nvapi_Stub_DLL" -eq 1; then
enable_nvcuda_CUDA_Support=1
fi
if test "$enable_ntdll_ForceBottomUpAlloc" -eq 1; then
if test "$enable_ntdll_Placeholders" -gt 1; then
abort "Patchset ntdll-Placeholders disabled, but ntdll-ForceBottomUpAlloc depends on that."
fi
enable_ntdll_Placeholders=1
fi
if test "$enable_ntdll_Builtin_Prot" -eq 1; then
if test "$enable_ntdll_WRITECOPY" -gt 1; then
abort "Patchset ntdll-WRITECOPY disabled, but ntdll-Builtin_Prot depends on that."
@ -2142,6 +2153,52 @@ if test "$enable_ntdll_Exception" -eq 1; then
patch_apply ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch
fi
# Patchset ntdll-Placeholders
# |
# | Modified files:
# | * dlls/kernelbase/memory.c, dlls/kernelbase/tests/process.c, dlls/ntdll/tests/virtual.c, dlls/ntdll/unix/server.c,
# | dlls/ntdll/unix/virtual.c, server/protocol.def
# |
if test "$enable_ntdll_Placeholders" -eq 1; then
patch_apply ntdll-Placeholders/0001-ntdll-tests-Add-tests-for-freeing-a-part-of-view.patch
patch_apply ntdll-Placeholders/0002-kernelbase-Validate-nonzero-size-for-MEM_RELEASE-in-.patch
patch_apply ntdll-Placeholders/0003-ntdll-Fix-size-validation-in-NtFreeVirtualMemory.patch
patch_apply ntdll-Placeholders/0004-ntdll-Fully-support-unaligned-views-in-free-ranges-m.patch
patch_apply ntdll-Placeholders/0005-ntdll-Factor-out-some-view-manipulation-functions.patch
patch_apply ntdll-Placeholders/0006-ntdll-Support-partial-view-release-in-NtFreeVirtualM.patch
patch_apply ntdll-Placeholders/0007-ntdll-Add-logging-for-free-ranges.patch
patch_apply ntdll-Placeholders/0008-ntdll-Handle-NULL-process-handle-in-MapViewOfFile3.patch
patch_apply ntdll-Placeholders/0009-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtFreeVirt.patch
patch_apply ntdll-Placeholders/0010-ntdll-Pass-allocation-type-to-map_view.patch
patch_apply ntdll-Placeholders/0011-ntdll-Support-MEM_RESERVE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0012-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0013-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-virtual_map.patch
patch_apply ntdll-Placeholders/0014-ntdll-tests-Add-more-tests-for-placeholders.patch
patch_apply ntdll-Placeholders/0015-ntdll-Support-MEM_COALESCE_PLACEHOLDERS-in-NtFreeVir.patch
patch_apply ntdll-Placeholders/0016-ntdll-Factor-out-unmap_view_of_section-function.patch
patch_apply ntdll-Placeholders/0017-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtUnmapVie.patch
fi
# Patchset ntdll-ForceBottomUpAlloc
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-Placeholders
# |
# | This patchset fixes the following Wine bugs:
# | * [#48175] AION (64 bit) - crashes in crysystem.dll.CryFree() due to high memory pointers allocated
# | * [#46568] 64-bit msxml6.dll from Microsoft Core XML Services 6.0 redist package fails to load (Wine doesn't respect
# | 44-bit user-mode VA limitation from Windows < 8.1)
# |
# | Modified files:
# | * dlls/ntdll/unix/virtual.c
# |
if test "$enable_ntdll_ForceBottomUpAlloc" -eq 1; then
patch_apply ntdll-ForceBottomUpAlloc/0001-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch
patch_apply ntdll-ForceBottomUpAlloc/0002-ntdll-Increase-free-ranges-view-block-size-on-64-bit.patch
patch_apply ntdll-ForceBottomUpAlloc/0003-ntdll-Force-virtual-memory-allocation-order.patch
patch_apply ntdll-ForceBottomUpAlloc/0004-ntdll-Exclude-natively-mapped-areas-from-free-areas-.patch
fi
# Patchset ntdll-HashLinks
# |
# | Modified files:
@ -2195,32 +2252,6 @@ if test "$enable_ntdll_NtSetLdtEntries" -eq 1; then
patch_apply ntdll-NtSetLdtEntries/0002-libs-wine-Allow-to-modify-reserved-LDT-entries.patch
fi
# Patchset ntdll-Placeholders
# |
# | Modified files:
# | * dlls/kernelbase/memory.c, dlls/kernelbase/tests/process.c, dlls/ntdll/tests/virtual.c, dlls/ntdll/unix/server.c,
# | dlls/ntdll/unix/virtual.c, server/protocol.def
# |
if test "$enable_ntdll_Placeholders" -eq 1; then
patch_apply ntdll-Placeholders/0001-ntdll-tests-Add-tests-for-freeing-a-part-of-view.patch
patch_apply ntdll-Placeholders/0002-kernelbase-Validate-nonzero-size-for-MEM_RELEASE-in-.patch
patch_apply ntdll-Placeholders/0003-ntdll-Fix-size-validation-in-NtFreeVirtualMemory.patch
patch_apply ntdll-Placeholders/0004-ntdll-Fully-support-unaligned-views-in-free-ranges-m.patch
patch_apply ntdll-Placeholders/0005-ntdll-Factor-out-some-view-manipulation-functions.patch
patch_apply ntdll-Placeholders/0006-ntdll-Support-partial-view-release-in-NtFreeVirtualM.patch
patch_apply ntdll-Placeholders/0007-ntdll-Add-logging-for-free-ranges.patch
patch_apply ntdll-Placeholders/0008-ntdll-Handle-NULL-process-handle-in-MapViewOfFile3.patch
patch_apply ntdll-Placeholders/0009-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtFreeVirt.patch
patch_apply ntdll-Placeholders/0010-ntdll-Pass-allocation-type-to-map_view.patch
patch_apply ntdll-Placeholders/0011-ntdll-Support-MEM_RESERVE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0012-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0013-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-virtual_map.patch
patch_apply ntdll-Placeholders/0014-ntdll-tests-Add-more-tests-for-placeholders.patch
patch_apply ntdll-Placeholders/0015-ntdll-Support-MEM_COALESCE_PLACEHOLDERS-in-NtFreeVir.patch
patch_apply ntdll-Placeholders/0016-ntdll-Factor-out-unmap_view_of_section-function.patch
patch_apply ntdll-Placeholders/0017-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtUnmapVie.patch
fi
# Patchset ntdll-ProcessQuotaLimits
# |
# | This patchset fixes the following Wine bugs: