Module: wine Branch: master Commit: 33240c54651ca849e91e8de649c0c779db01d064 URL: https://gitlab.winehq.org/wine/wine/-/commit/33240c54651ca849e91e8de649c0c77...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Jun 7 12:00:14 2023 +0200
ntdll: Reimplement map_fixed_area() to avoid recursion and callbacks.
---
dlls/ntdll/unix/virtual.c | 110 ++++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 76 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 074fe7a4559..f3362a8b6ef 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1463,42 +1463,6 @@ 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. - * virtual_mutex 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; -} - - /*********************************************************************** * unmap_area * @@ -1918,52 +1882,48 @@ static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg ) /*********************************************************************** * map_fixed_area * - * mmap the fixed memory area. + * Map a memory area at a fixed address. * virtual_mutex must be held by caller. */ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) { - void *ptr; + int unix_prot = get_unix_prot(vprot); + struct reserved_area *area; + NTSTATUS status; + char *start = base, *end = (char *)base + size;
- switch (mmap_is_in_reserved_area( base, size )) - { - case -1: /* partially in a reserved area */ + if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES; + + LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) { - NTSTATUS status; - struct area_boundary area; - size_t lower_size; - area.base = base; - area.size = size; - 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) + char *area_start = area->base; + char *area_end = area_start + area->size; + + if (area_start >= end) break; + if (area_end <= start) continue; + if (area_start > start) { - status = map_fixed_area( area.boundary, size - lower_size, vprot); - if (status != STATUS_SUCCESS) unmap_area( base, lower_size ); + if (anon_mmap_tryfixed( start, area_start - start, unix_prot, 0 ) == MAP_FAILED) goto failed; + start = area_start; } - return status; - } - case 0: /* not in a reserved area, do a normal allocation */ - if ((ptr = anon_mmap_tryfixed( base, size, get_unix_prot(vprot), 0 )) == MAP_FAILED) + if (area_end >= end) { - if (errno == ENOMEM) return STATUS_NO_MEMORY; - if (errno == EEXIST) return STATUS_CONFLICTING_ADDRESSES; - return STATUS_INVALID_PARAMETER; + if (anon_mmap_fixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; + return STATUS_SUCCESS; } - 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 = anon_mmap_fixed( base, size, get_unix_prot(vprot), 0 )) != base) - return STATUS_INVALID_PARAMETER; - break; + if (anon_mmap_fixed( start, area_end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; + start = area_end; } - if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit; + + if (anon_mmap_tryfixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; return STATUS_SUCCESS; + +failed: + if (errno == ENOMEM) status = STATUS_NO_MEMORY; + else if (errno == EEXIST) status = STATUS_CONFLICTING_ADDRESSES; + else status = STATUS_INVALID_PARAMETER; + unmap_area( base, start - (char *)base ); + return status; }
/*********************************************************************** @@ -1998,12 +1958,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
if (base) { - if (is_beyond_limit( base, size, address_space_limit )) - return STATUS_WORKING_SET_LIMIT_RANGE; - if (limit && is_beyond_limit( base, size, (void *)limit )) - return STATUS_CONFLICTING_ADDRESSES; - status = map_fixed_area( base, size, vprot ); - if (status != STATUS_SUCCESS) return status; + if (is_beyond_limit( base, size, address_space_limit )) return STATUS_WORKING_SET_LIMIT_RANGE; + if (limit && is_beyond_limit( base, size, (void *)limit )) return STATUS_CONFLICTING_ADDRESSES; + if ((status = map_fixed_area( base, size, vprot ))) return status; + if (is_beyond_limit( base, size, working_set_limit )) working_set_limit = address_space_limit; ptr = base; } else