Alexandre Julliard : ntdll: Add a helper function to try an mmap at a fixed address.
Alexandre Julliard
julliard at winehq.org
Thu Sep 3 15:26:46 CDT 2020
Module: wine
Branch: master
Commit: 4e80f2ea5e350168933599ab7ad633254717e93c
URL: https://source.winehq.org/git/wine.git/?a=commit;h=4e80f2ea5e350168933599ab7ad633254717e93c
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu Sep 3 10:54:17 2020 +0200
ntdll: Add a helper function to try an mmap at a fixed address.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/virtual.c | 112 ++++++++++++++++++++++++----------------------
1 file changed, 58 insertions(+), 54 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 907524ecc5..22d328b1ce 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -59,7 +59,6 @@
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
-#include "wine/library.h"
#include "wine/exception.h"
#include "wine/list.h"
#include "wine/rbtree.h"
@@ -173,12 +172,6 @@ static struct list teb_list = LIST_INIT( teb_list );
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
#endif
-#ifndef MAP_TRYFIXED
-#define MAP_TRYFIXED 0
-#endif
-#ifndef MAP_FIXED_NOREPLACE
-#define MAP_FIXED_NOREPLACE 0
-#endif
#ifdef _WIN64 /* on 64-bit the page protection bytes use a 2-level table */
static const size_t pages_vprot_shift = 20;
@@ -211,6 +204,11 @@ static inline BOOL is_inside_signal_stack( void *ptr )
(char *)ptr < (char *)get_signal_stack() + signal_stack_size);
}
+static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit )
+{
+ return (addr >= limit || (const char *)addr + size > (const char *)limit);
+}
+
/* mmap() anonymous memory at a fixed address */
void *anon_mmap_fixed( void *start, size_t size, int prot, int flags )
{
@@ -375,6 +373,48 @@ static int mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T s
return ret;
}
+static void *anon_mmap_tryfixed( void *start, size_t size, int prot, int flags )
+{
+ void *ptr;
+
+#ifdef MAP_FIXED_NOREPLACE
+ ptr = mmap( start, size, prot, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON | flags, -1, 0 );
+#elif defined(MAP_TRYFIXED)
+ ptr = mmap( start, size, prot, MAP_TRYFIXED | MAP_PRIVATE | MAP_ANON | flags, -1, 0 );
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ ptr = mmap( start, size, prot, MAP_FIXED | MAP_EXCL | MAP_PRIVATE | MAP_ANON | flags, -1, 0 );
+ if (ptr == MAP_FAILED && errno == EINVAL) errno = EEXIST;
+#elif defined(__APPLE__)
+ mach_vm_address_t result = (mach_vm_address_t)start;
+ kern_return_t ret = mach_vm_map( mach_task_self(), &result, size, 0, VM_FLAGS_FIXED,
+ MEMORY_OBJECT_NULL, 0, 0, prot, VM_PROT_ALL, VM_INHERIT_COPY );
+
+ if (!ret)
+ {
+ if ((ptr = anon_mmap_fixed( start, size, prot, flags )) == MAP_FAILED)
+ mach_vm_deallocate( mach_task_self(), result, size );
+ }
+ else
+ {
+ errno = (ret == KERN_NO_SPACE ? EEXIST : ENOMEM);
+ ptr = MAP_FAILED;
+ }
+#else
+ ptr = mmap( start, size, prot, MAP_PRIVATE | MAP_ANON | flags, -1, 0 );
+#endif
+ if (ptr != MAP_FAILED && ptr != start)
+ {
+ if (is_beyond_limit( ptr, size, user_space_limit ))
+ {
+ anon_mmap_fixed( ptr, size, PROT_NONE, MAP_NORESERVE );
+ mmap_add_reserved_area( ptr, size );
+ }
+ else munmap( ptr, size );
+ ptr = MAP_FAILED;
+ errno = EEXIST;
+ }
+ return ptr;
+}
static void reserve_area( void *addr, void *end )
{
@@ -432,23 +472,15 @@ static void reserve_area( void *addr, void *end )
}
#else
void *ptr;
- int flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_TRYFIXED;
size_t size = (char *)end - (char *)addr;
if (!size) return;
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- ptr = mmap( addr, size, PROT_NONE, flags | MAP_FIXED | MAP_EXCL, -1, 0 );
-#else
- ptr = mmap( addr, size, PROT_NONE, flags, -1, 0 );
-#endif
- if (ptr == addr)
+ if ((ptr = anon_mmap_tryfixed( addr, size, PROT_NONE, MAP_NORESERVE )) != MAP_FAILED)
{
mmap_add_reserved_area( addr, size );
return;
}
- if (ptr != (void *)-1) munmap( ptr, size );
-
size = (size / 2) & ~granularity_mask;
if (size)
{
@@ -1028,20 +1060,14 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step,
while (start && base <= start && (char*)start + size <= (char*)end)
{
- if ((ptr = wine_anon_mmap( start, size, unix_prot, MAP_FIXED_NOREPLACE )) == start)
- return start;
+ if ((ptr = anon_mmap_tryfixed( start, size, unix_prot, 0 )) != MAP_FAILED) return start;
TRACE( "Found free area is already mapped, start %p.\n", start );
-
- if (ptr == (void *)-1 && errno != EEXIST)
+ if (errno != EEXIST)
{
- ERR( "wine_anon_mmap() error %s, range %p-%p, unix_prot %#x.\n",
- strerror(errno), start, (char *)start + size, unix_prot );
+ ERR( "mmap() error %s, range %p-%p, unix_prot %#x.\n",
+ strerror(errno), start, (char *)start + size, unix_prot );
return NULL;
}
-
- if (ptr != (void *)-1)
- munmap( ptr, size );
-
if ((step > 0 && (char *)end - (char *)start < step) ||
(step < 0 && (char *)start - (char *)base < -step) ||
step == 0)
@@ -1243,17 +1269,6 @@ static int CDECL get_area_boundary_callback( void *start, SIZE_T size, void *arg
}
-/***********************************************************************
- * is_beyond_limit
- *
- * Check if an address range goes beyond a given limit.
- */
-static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit )
-{
- return (addr >= limit || (const char *)addr + size > (const char *)limit);
-}
-
-
/***********************************************************************
* unmap_area
*
@@ -1678,18 +1693,12 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
return status;
}
case 0: /* not in a reserved area, do a normal allocation */
- if ((ptr = wine_anon_mmap( base, size, get_unix_prot(vprot), 0 )) == (void *)-1)
+ if ((ptr = anon_mmap_tryfixed( base, size, get_unix_prot(vprot), 0 )) == MAP_FAILED)
{
if (errno == ENOMEM) return STATUS_NO_MEMORY;
+ if (errno == EEXIST) return STATUS_CONFLICTING_ADDRESSES;
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:
@@ -1917,20 +1926,16 @@ static NTSTATUS allocate_dos_memory( struct file_view **view, unsigned int vprot
if (mmap_is_in_reserved_area( low_64k, dosmem_size - 0x10000 ) != 1)
{
- addr = wine_anon_mmap( low_64k, dosmem_size - 0x10000, unix_prot, 0 );
- if (addr != low_64k)
- {
- if (addr != (void *)-1) munmap( addr, dosmem_size - 0x10000 );
- return map_view( view, NULL, dosmem_size, FALSE, vprot, 0 );
- }
+ addr = anon_mmap_tryfixed( low_64k, dosmem_size - 0x10000, unix_prot, 0 );
+ if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, FALSE, vprot, 0 );
}
/* now try to allocate the low 64K too */
if (mmap_is_in_reserved_area( NULL, 0x10000 ) != 1)
{
- addr = wine_anon_mmap( (void *)page_size, 0x10000 - page_size, unix_prot, 0 );
- if (addr == (void *)page_size)
+ addr = anon_mmap_tryfixed( (void *)page_size, 0x10000 - page_size, unix_prot, 0 );
+ if (addr != MAP_FAILED)
{
if (!anon_mmap_fixed( NULL, page_size, unix_prot, 0 ))
{
@@ -1941,7 +1946,6 @@ static NTSTATUS allocate_dos_memory( struct file_view **view, unsigned int vprot
}
else
{
- if (addr != (void *)-1) munmap( addr, 0x10000 - page_size );
addr = low_64k;
TRACE( "failed to map low 64K range\n" );
}
More information about the wine-cvs
mailing list