[PATCH 7/8] ntdll: Use custom internal zero_bits_64 parameter format

Rémi Bernon rbernon at codeweavers.com
Thu Aug 1 03:07:44 CDT 2019


The zero_bits parameter can be a pointer mask on Win64 and WoW64 and it
was incorrectly truncated to 16bits in APCs. Testing shows that only the
leading zeroes are used in the mask, so we can safely use the 64 based
number of leading zeroes everywhere instead.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 configure.ac            |  9 +++++
 dlls/ntdll/ntdll_misc.h |  4 +-
 dlls/ntdll/server.c     |  4 +-
 dlls/ntdll/virtual.c    | 88 ++++++++++++++++++++++++++++-------------
 server/protocol.def     | 28 ++++++-------
 server/trace.c          |  8 ++--
 6 files changed, 92 insertions(+), 49 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0fe26022b7d..1684400cd17 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2693,6 +2693,15 @@ then
     AC_DEFINE(HAVE___BUILTIN_CLZ, 1, [Define to 1 if you have the `__builtin_clz' built-in function.])
 fi
 
+dnl Check for __builtin_clzll
+AC_CACHE_CHECK([for __builtin_clzll], ac_cv_have___builtin_clzll,
+               AC_LINK_IFELSE([AC_LANG_PROGRAM(,[[return __builtin_clzll(1)]])],
+               [ac_cv_have___builtin_clzll="yes"], [ac_cv_have___builtin_clzll="no"]))
+if test "$ac_cv_have___builtin_clzll" = "yes"
+then
+    AC_DEFINE(HAVE___BUILTIN_CLZLL, 1, [Define to 1 if you have the `__builtin_clzll' built-in function.])
+fi
+
 dnl Check for __builtin_popcount
 AC_CACHE_CHECK([for __builtin_popcount], ac_cv_have___builtin_popcount,
                AC_LINK_IFELSE([AC_LANG_PROGRAM(,[[return __builtin_popcount(1)]])],
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 1950d8c1c7e..5ddce437cfb 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -163,9 +163,9 @@ extern NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_S
                                            UINT disposition ) DECLSPEC_HIDDEN;
 
 /* virtual memory */
-extern NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr,
+extern NTSTATUS virtual_alloc_aligned( PVOID *ret, unsigned short zero_bits_64, SIZE_T *size_ptr,
                                        ULONG type, ULONG protect, ULONG alignment ) DECLSPEC_HIDDEN;
-extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, SIZE_T commit_size,
+extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size,
                                      const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type,
                                      ULONG protect, pe_image_info_t *image_info ) DECLSPEC_HIDDEN;
 extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 16e73d497c4..204370a1b77 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -431,7 +431,7 @@ BOOL invoke_apc( const apc_call_t *call, apc_result_t *result )
         if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size)
         {
             result->virtual_alloc.status = virtual_alloc_aligned( &addr,
-                                                                  call->virtual_alloc.zero_bits, &size,
+                                                                  call->virtual_alloc.zero_bits_64, &size,
                                                                   call->virtual_alloc.op_type,
                                                                   call->virtual_alloc.prot,
                                                                   0 );
@@ -538,7 +538,7 @@ BOOL invoke_apc( const apc_call_t *call, apc_result_t *result )
             offset.QuadPart = call->map_view.offset;
             result->map_view.status = virtual_map_section( wine_server_ptr_handle(call->map_view.handle),
                                                            &addr,
-                                                           call->map_view.zero_bits, 0,
+                                                           call->map_view.zero_bits_64, 0,
                                                            &offset, &size,
                                                            call->map_view.alloc_type, call->map_view.prot,
                                                            &image_info );
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 57536eb6295..965b4a55ce8 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -418,6 +418,38 @@ static inline UINT_PTR get_mask( ULONG alignment )
 }
 
 
+/***********************************************************************
+ *           zero_bits_win_to_64
+ *
+ * Convert from Windows hybrid 32bit-based / bitmask to 64bit-based format
+ */
+static inline unsigned short zero_bits_win_to_64( ULONG_PTR zero_bits )
+{
+    UINT_PTR mask;
+    unsigned short zero_bits_64;
+
+    if (zero_bits == 0) return 0;
+    if (zero_bits < 32) return 32 + zero_bits;
+    mask = zero_bits;
+
+#ifdef HAVE___BUILTIN_CLZLL
+    zero_bits_64 = __builtin_clzll( mask );
+#else
+    zero_bits_64 = 63;
+#ifdef _WIN64
+    if (mask >> 32) { zero_bits_64 -= 32; mask >>= 32; }
+#endif
+    if (mask >> 16) { zero_bits_64 -= 16; mask >>= 16; }
+    if (mask >> 8) { zero_bits_64 -= 8; mask >>= 8; }
+    if (mask >> 4) { zero_bits_64 -= 4; mask >>= 4; }
+    if (mask >> 2) { zero_bits_64 -= 2; mask >>= 2; }
+    if (mask >> 1) { zero_bits_64 -= 1; }
+#endif
+
+    return zero_bits_64;
+}
+
+
 /***********************************************************************
  *           is_write_watch_range
  */
@@ -1083,7 +1115,7 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
  * The csVirtual section must be held by caller.
  */
 static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, size_t alignment,
-                          int top_down, unsigned int vprot, size_t zero_bits )
+                          int top_down, unsigned int vprot, unsigned short zero_bits_64 )
 {
     void *ptr;
     NTSTATUS status;
@@ -1102,7 +1134,7 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
         size_t view_size = size + mask + 1;
         struct alloc_area alloc;
 
-        if (zero_bits)
+        if (zero_bits_64)
             FIXME("Unimplemented zero_bits parameter value\n");
 
         alloc.size = size;
@@ -1361,7 +1393,7 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable )
  *
  * Map an executable (PE format) image into memory.
  */
-static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_down, SIZE_T zero_bits,
+static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_down, unsigned short zero_bits_64,
                            pe_image_info_t *image_info, int shared_fd, BOOL removable, PVOID *addr_ptr )
 {
     IMAGE_DOS_HEADER *dos;
@@ -1392,11 +1424,11 @@ static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_
 
     if (base >= (char *)address_space_start)  /* make sure the DOS area remains free */
         status = map_view( &view, base, total_size, 0, top_down, SEC_IMAGE | SEC_FILE |
-                           VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits );
+                           VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits_64 );
 
     if (status != STATUS_SUCCESS)
         status = map_view( &view, NULL, total_size, 0, top_down, SEC_IMAGE | SEC_FILE |
-                           VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits );
+                           VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY, zero_bits_64 );
 
     if (status != STATUS_SUCCESS) goto error;
 
@@ -1611,7 +1643,7 @@ static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, int top_
  *
  * Map a file section into memory.
  */
-NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, SIZE_T commit_size,
+NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size,
                               const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type,
                               ULONG protect, pe_image_info_t *image_info )
 {
@@ -1673,14 +1705,14 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S
 
             if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
                                            &shared_fd, &shared_needs_close, NULL, NULL ))) goto done;
-            res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits, image_info,
+            res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info,
                              shared_fd, needs_close, addr_ptr );
             if (shared_needs_close) close( shared_fd );
             close_handle( shared_file );
         }
         else
         {
-            res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits, image_info,
+            res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info,
                              -1, needs_close, addr_ptr );
         }
         if (needs_close) close( unix_handle );
@@ -1718,7 +1750,7 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S
     get_vprot_flags( protect, &vprot, sec_flags & SEC_IMAGE );
     vprot |= sec_flags;
     if (!(sec_flags & SEC_RESERVE)) vprot |= VPROT_COMMITTED;
-    res = map_view( &view, *addr_ptr, size, 0, alloc_type & MEM_TOP_DOWN, vprot, zero_bits );
+    res = map_view( &view, *addr_ptr, size, 0, alloc_type & MEM_TOP_DOWN, vprot, zero_bits_64 );
     if (res)
     {
         server_leave_uninterrupted_section( &csVirtual, &sigset );
@@ -2506,6 +2538,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
 {
     SIZE_T size = *size_ptr;
     NTSTATUS status = STATUS_SUCCESS;
+    unsigned short zero_bits_64 = zero_bits_win_to_64( zero_bits );
 
     TRACE("%p %p %08lx %x %08x\n", process, *ret, size, type, protect );
 
@@ -2520,12 +2553,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
 
         memset( &call, 0, sizeof(call) );
 
-        call.virtual_alloc.type      = APC_VIRTUAL_ALLOC;
-        call.virtual_alloc.addr      = wine_server_client_ptr( *ret );
-        call.virtual_alloc.size      = *size_ptr;
-        call.virtual_alloc.zero_bits = zero_bits;
-        call.virtual_alloc.op_type   = type;
-        call.virtual_alloc.prot      = protect;
+        call.virtual_alloc.type         = APC_VIRTUAL_ALLOC;
+        call.virtual_alloc.addr         = wine_server_client_ptr( *ret );
+        call.virtual_alloc.size         = *size_ptr;
+        call.virtual_alloc.zero_bits_64 = zero_bits_64;
+        call.virtual_alloc.op_type      = type;
+        call.virtual_alloc.prot         = protect;
         status = server_queue_process_apc( process, &call, &result );
         if (status != STATUS_SUCCESS) return status;
 
@@ -2537,7 +2570,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
         return result.virtual_alloc.status;
     }
 
-    return virtual_alloc_aligned( ret, zero_bits, size_ptr, type, protect, 0 );
+    return virtual_alloc_aligned( ret, zero_bits_64, size_ptr, type, protect, 0 );
 }
 
 
@@ -2546,7 +2579,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
  *
  * Same as NtAllocateVirtualMemory but with an alignment parameter
  */
-NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr,
+NTSTATUS virtual_alloc_aligned( PVOID *ret, unsigned short zero_bits_64, SIZE_T *size_ptr,
                                 ULONG type, ULONG protect, ULONG alignment )
 {
     void *base;
@@ -2608,7 +2641,7 @@ NTSTATUS virtual_alloc_aligned( PVOID *ret, ULONG zero_bits, SIZE_T *size_ptr,
 
             if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION;
             else if (is_dos_memory) status = allocate_dos_memory( &view, vprot );
-            else status = map_view( &view, base, size, alignment, type & MEM_TOP_DOWN, vprot, zero_bits );
+            else status = map_view( &view, base, size, alignment, type & MEM_TOP_DOWN, vprot, zero_bits_64 );
 
             if (status == STATUS_SUCCESS) base = view->base;
         }
@@ -3140,6 +3173,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
     SIZE_T mask = get_mask( 0 );
     pe_image_info_t image_info;
     LARGE_INTEGER offset;
+    unsigned short zero_bits_64 = zero_bits_win_to_64( zero_bits );
 
     offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0;
 
@@ -3178,14 +3212,14 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
 
         memset( &call, 0, sizeof(call) );
 
-        call.map_view.type        = APC_MAP_VIEW;
-        call.map_view.handle      = wine_server_obj_handle( handle );
-        call.map_view.addr        = wine_server_client_ptr( *addr_ptr );
-        call.map_view.size        = *size_ptr;
-        call.map_view.offset      = offset.QuadPart;
-        call.map_view.zero_bits   = zero_bits;
-        call.map_view.alloc_type  = alloc_type;
-        call.map_view.prot        = protect;
+        call.map_view.type         = APC_MAP_VIEW;
+        call.map_view.handle       = wine_server_obj_handle( handle );
+        call.map_view.addr         = wine_server_client_ptr( *addr_ptr );
+        call.map_view.size         = *size_ptr;
+        call.map_view.offset       = offset.QuadPart;
+        call.map_view.zero_bits_64 = zero_bits_64;
+        call.map_view.alloc_type   = alloc_type;
+        call.map_view.prot         = protect;
         res = server_queue_process_apc( process, &call, &result );
         if (res != STATUS_SUCCESS) return res;
 
@@ -3197,7 +3231,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
         return result.map_view.status;
     }
 
-    return virtual_map_section( handle, addr_ptr, zero_bits, commit_size,
+    return virtual_map_section( handle, addr_ptr, zero_bits_64, commit_size,
                                 offset_ptr, size_ptr, alloc_type, protect,
                                 &image_info );
 }
diff --git a/server/protocol.def b/server/protocol.def
index 8157199f2fa..6af0ae0cff8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -496,12 +496,12 @@ typedef union
     } async_io;
     struct
     {
-        enum apc_type    type;      /* APC_VIRTUAL_ALLOC */
-        unsigned int     op_type;   /* type of operation */
-        client_ptr_t     addr;      /* requested address */
-        mem_size_t       size;      /* allocation size */
-        unsigned int     zero_bits; /* allocation alignment */
-        unsigned int     prot;      /* memory protection flags */
+        enum apc_type    type;         /* APC_VIRTUAL_ALLOC */
+        unsigned int     op_type;      /* type of operation */
+        client_ptr_t     addr;         /* requested address */
+        mem_size_t       size;         /* allocation size */
+        unsigned int     zero_bits_64; /* number of zero high bits */
+        unsigned int     prot;         /* memory protection flags */
     } virtual_alloc;
     struct
     {
@@ -546,14 +546,14 @@ typedef union
     } virtual_unlock;
     struct
     {
-        enum apc_type    type;      /* APC_MAP_VIEW */
-        obj_handle_t     handle;    /* mapping handle */
-        client_ptr_t     addr;      /* requested address */
-        mem_size_t       size;      /* allocation size */
-        file_pos_t       offset;    /* file offset */
-        unsigned int     alloc_type;/* allocation type */
-        unsigned short   zero_bits; /* allocation alignment */
-        unsigned short   prot;      /* memory protection flags */
+        enum apc_type    type;         /* APC_MAP_VIEW */
+        obj_handle_t     handle;       /* mapping handle */
+        client_ptr_t     addr;         /* requested address */
+        mem_size_t       size;         /* allocation size */
+        file_pos_t       offset;       /* file offset */
+        unsigned int     alloc_type;   /* allocation type */
+        unsigned short   zero_bits_64; /* number of zero high bits */
+        unsigned short   prot;         /* memory protection flags */
     } map_view;
     struct
     {
diff --git a/server/trace.c b/server/trace.c
index 0df649ea295..615542cff52 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -171,8 +171,8 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call )
     case APC_VIRTUAL_ALLOC:
         dump_uint64( "APC_VIRTUAL_ALLOC,addr==", &call->virtual_alloc.addr );
         dump_uint64( ",size=", &call->virtual_alloc.size );
-        fprintf( stderr, ",zero_bits=%u,op_type=%x,prot=%x",
-                 call->virtual_alloc.zero_bits, call->virtual_alloc.op_type,
+        fprintf( stderr, ",zero_bits_64=%u,op_type=%x,prot=%x",
+                 call->virtual_alloc.zero_bits_64, call->virtual_alloc.op_type,
                  call->virtual_alloc.prot );
         break;
     case APC_VIRTUAL_FREE:
@@ -205,8 +205,8 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call )
         dump_uint64( ",addr=", &call->map_view.addr );
         dump_uint64( ",size=", &call->map_view.size );
         dump_uint64( ",offset=", &call->map_view.offset );
-        fprintf( stderr, ",zero_bits=%u,alloc_type=%x,prot=%x",
-                 call->map_view.zero_bits, call->map_view.alloc_type, call->map_view.prot );
+        fprintf( stderr, ",zero_bits_64=%u,alloc_type=%x,prot=%x",
+                 call->map_view.zero_bits_64, call->map_view.alloc_type, call->map_view.prot );
         break;
     case APC_UNMAP_VIEW:
         dump_uint64( "APC_UNMAP_VIEW,addr=", &call->unmap_view.addr );
-- 
2.20.1




More information about the wine-devel mailing list