Module: wine Branch: master Commit: 47404fb36cc2db312fcf4b7fdddfdedbd75b78b5 URL: https://gitlab.winehq.org/wine/wine/-/commit/47404fb36cc2db312fcf4b7fdddfded...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Jun 7 12:12:02 2023 +0200
ntdll: Reimplement allocation inside a reserved area without using a callback.
And make the allocation limits more explicit.
---
dlls/ntdll/unix/virtual.c | 118 +++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 44 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index f3362a8b6ef..0de7619ff86 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1390,7 +1390,7 @@ static void *map_free_area( void *base, void *end, size_t size, int top_down, in * * Find a free area between views inside the specified range. * virtual_mutex must be held by caller. - * The range must be inside the preloader reserved range. + * The range must be inside a reserved area. */ static void *find_reserved_free_area( void *base, void *end, size_t size, int top_down, size_t align_mask ) { @@ -1831,52 +1831,88 @@ static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t want }
-struct alloc_area -{ - size_t size; - int top_down; - void *limit; - void *result; - size_t align_mask; -}; - /*********************************************************************** - * alloc_reserved_area_callback + * find_reserved_free_area_outside_preloader * - * Try to map some space inside a reserved area. Callback for mmap_enum_reserved_areas. + * Find a free area inside a reserved area, skipping the preloader reserved range. + * virtual_mutex must be held by caller. */ -static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg ) +static void *find_reserved_free_area_outside_preloader( void *start, void *end, size_t size, + int top_down, size_t align_mask ) { - 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; + void *ret;
- /* make sure we don't touch the preloader reserved range */ - if (preload_reserve_end >= start) + if (preload_reserve_end >= end) + { + if (preload_reserve_start <= start) return NULL; /* no space in that area */ + if (preload_reserve_start < end) end = preload_reserve_start; + } + else if (preload_reserve_start <= start) { - if (preload_reserve_end >= end) + if (preload_reserve_end > start) start = preload_reserve_end; + } + else /* range is split in two by the preloader reservation, try both parts */ + { + if (top_down) { - if (preload_reserve_start <= start) return 0; /* no space in that area */ - if (preload_reserve_start < end) end = preload_reserve_start; + ret = find_reserved_free_area( preload_reserve_end, end, size, top_down, align_mask ); + if (ret) return ret; + end = preload_reserve_start; } - else if (preload_reserve_start <= start) start = preload_reserve_end; else { - /* 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->align_mask ))) - return 1; - /* then fall through to try second part */ + ret = find_reserved_free_area( start, preload_reserve_start, size, top_down, align_mask ); + if (ret) return ret; start = preload_reserve_end; } } - if ((alloc->result = find_reserved_free_area( start, end, alloc->size, alloc->top_down, alloc->align_mask ))) - return 1; + return find_reserved_free_area( start, end, size, top_down, align_mask ); +}
- return 0; +/*********************************************************************** + * map_reserved_area + * + * Try to map some space inside a reserved area. + * virtual_mutex must be held by caller. + */ +static void *map_reserved_area( void *limit_low, void *limit_high, size_t size, int top_down, + int unix_prot, size_t align_mask ) +{ + void *ptr = NULL; + struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry ); + + if (top_down) + { + LIST_FOR_EACH_ENTRY_REV( area, &reserved_areas, struct reserved_area, entry ) + { + void *start = area->base; + void *end = (char *)start + area->size; + + if (start >= limit_high) continue; + if (end <= limit_low) return NULL; + if (start < limit_low) start = limit_low; + if (end > limit_high) end = limit_high; + ptr = find_reserved_free_area_outside_preloader( start, end, size, top_down, align_mask ); + if (ptr) break; + } + } + else + { + LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) + { + void *start = area->base; + void *end = (char *)start + area->size; + + if (start >= limit_high) return NULL; + if (end <= limit_low) continue; + if (start < limit_low) start = limit_low; + if (end > limit_high) end = limit_high; + ptr = find_reserved_free_area_outside_preloader( start, end, size, top_down, align_mask ); + if (ptr) break; + } + } + if (ptr && anon_mmap_fixed( ptr, size, unix_prot, 0 ) != ptr) ptr = NULL; + return ptr; }
/*********************************************************************** @@ -1966,30 +2002,24 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, } else { - struct alloc_area alloc; + void *start = address_space_start; + void *end = user_space_limit; size_t view_size, unmap_size;
if (!align_mask) align_mask = granularity_mask; view_size = size + align_mask + 1;
- alloc.size = size; - alloc.top_down = top_down; - alloc.limit = limit ? min( (void *)(limit + 1), user_space_limit ) : user_space_limit; - alloc.align_mask = align_mask; + if (limit && (void *)limit < end) end = (char *)limit + 1;
- if (mmap_enum_reserved_areas( alloc_reserved_area_callback, &alloc, top_down )) + if ((ptr = map_reserved_area( start, end, size, top_down, get_unix_prot(vprot), align_mask ))) { - ptr = alloc.result; TRACE( "got mem in reserved area %p-%p\n", ptr, (char *)ptr + size ); - if (anon_mmap_fixed( ptr, size, get_unix_prot(vprot), 0 ) != ptr) - return STATUS_INVALID_PARAMETER; goto done; }
if (limit) { - if (!(ptr = map_free_area( address_space_start, alloc.limit, size, - top_down, get_unix_prot(vprot), align_mask ))) + if (!(ptr = map_free_area( start, end, size, 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;