ntdll: Use custom internal zero_bits_64 parameter format.

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@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2019-08-01 10:07:44 +02:00 committed by Alexandre Julliard
parent f172dd03ff
commit 6672fc9d85
6 changed files with 77 additions and 51 deletions

View File

@ -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;

View File

@ -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 );

View File

@ -418,6 +418,30 @@ 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 )
{
unsigned short zero_bits_64;
if (zero_bits == 0) return 0;
if (zero_bits < 32) return 32 + zero_bits;
zero_bits_64 = 63;
#ifdef _WIN64
if (zero_bits >> 32) { zero_bits_64 -= 32; zero_bits >>= 32; }
#endif
if (zero_bits >> 16) { zero_bits_64 -= 16; zero_bits >>= 16; }
if (zero_bits >> 8) { zero_bits_64 -= 8; zero_bits >>= 8; }
if (zero_bits >> 4) { zero_bits_64 -= 4; zero_bits >>= 4; }
if (zero_bits >> 2) { zero_bits_64 -= 2; zero_bits >>= 2; }
if (zero_bits >> 1) { zero_bits_64 -= 1; }
return zero_bits_64;
}
/***********************************************************************
* is_write_watch_range
*/
@ -1083,7 +1107,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 +1126,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 +1385,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 +1416,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 +1635,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 +1697,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 +1742,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 +2530,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 +2545,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 +2562,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 +2571,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 +2633,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 +3165,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 +3204,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 +3223,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 );
}

View File

@ -484,7 +484,7 @@ typedef union
unsigned int op_type;
client_ptr_t addr;
mem_size_t size;
unsigned int zero_bits;
unsigned int zero_bits_64;
unsigned int prot;
} virtual_alloc;
struct
@ -536,7 +536,7 @@ typedef union
mem_size_t size;
file_pos_t offset;
unsigned int alloc_type;
unsigned short zero_bits;
unsigned short zero_bits_64;
unsigned short prot;
} map_view;
struct

View File

@ -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
{

View File

@ -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 );