diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 2c5e1d6ecc3..6831fe3c522 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -584,6 +584,48 @@ static void test_NtAllocateVirtualMemoryEx_address_requirements(void) size = 0; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); ok(!status, "Unexpected status %08lx.\n", status); + + a.HighestEndingAddress = (void *)(0x20001000 - 1); + a.Alignment = 0x20000000; + size = 0x2000; + addr = NULL; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(status == STATUS_NO_MEMORY, "Unexpected status %08lx.\n", status); + + a.HighestEndingAddress = NULL; + a.Alignment = 0x8000; + size = 0x1000; + addr = NULL; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + + a.Alignment = 0x30000; + size = 0x1000; + addr = NULL; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + + a.Alignment = 0x40000; + size = 0x1000; + addr = NULL; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(!status, "Unexpected status %08lx.\n", status); + ok(!((ULONG_PTR)addr & 0x3ffff), "Unexpected addr %p.\n", addr); + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_COMMIT, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + ok(!status, "Unexpected status %08lx.\n", status); + + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr, &size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE, ext, 1); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); } struct test_stack_size_thread_args diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index b7d8733f2bc..07d9c8d3acd 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -358,7 +358,7 @@ static NTSTATUS invoke_user_apc( CONTEXT *context, const user_apc_t *apc, NTSTAT */ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOOL self ) { - SIZE_T size, bits, limit; + SIZE_T size, bits, limit, align; void *addr; memset( result, 0, sizeof(*result) ); @@ -416,9 +416,12 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO addr = wine_server_get_ptr( call->virtual_alloc_ex.addr ); size = call->virtual_alloc_ex.size; limit = min( (ULONG_PTR)sbi.HighestUserAddress, call->virtual_alloc_ex.limit ); - if ((ULONG_PTR)addr == call->virtual_alloc_ex.addr && size == call->virtual_alloc_ex.size) + align = call->virtual_alloc_ex.align; + if ((ULONG_PTR)addr == call->virtual_alloc_ex.addr && size == call->virtual_alloc_ex.size + && align == call->virtual_alloc_ex.align) { r.HighestEndingAddress = (void *)limit; + r.Alignment = align; result->virtual_alloc_ex.status = NtAllocateVirtualMemoryEx( NtCurrentProcess(), &addr, &size, call->virtual_alloc_ex.op_type, call->virtual_alloc_ex.prot, &ext, 1 ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b1caaff8a13..3367913d4e2 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3738,7 +3738,7 @@ void virtual_set_large_address_space(void) * NtAllocateVirtualMemory[Ex] implementation. */ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG type, ULONG protect, - ULONG_PTR limit ) + ULONG_PTR limit, ULONG_PTR align ) { void *base; unsigned int vprot; @@ -3800,7 +3800,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ 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, type & MEM_TOP_DOWN, vprot, limit, - granularity_mask ); + align ? align - 1 : granularity_mask ); if (status == STATUS_SUCCESS) base = view->base; } @@ -3888,7 +3888,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z else limit = 0; - return allocate_virtual_memory( ret, size_ptr, type, protect, limit ); + return allocate_virtual_memory( ret, size_ptr, type, protect, limit, 0 ); } @@ -3901,6 +3901,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s ULONG count ) { ULONG_PTR limit = 0; + ULONG_PTR align = 0; TRACE("%p %p %08lx %x %08x %p %u\n", process, *ret, *size_ptr, type, protect, parameters, count ); @@ -3930,17 +3931,27 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s } r = (MEM_ADDRESS_REQUIREMENTS *)parameters[i].Pointer; - if (r->LowestStartingAddress || r->Alignment) + if (r->LowestStartingAddress) FIXME( "Not supported requirements LowestStartingAddress %p, Alignment %p.\n", r->LowestStartingAddress, (void *)r->Alignment ); + if (r->Alignment) + { + if (*ret || (r->Alignment & (r->Alignment - 1)) || r->Alignment - 1 < granularity_mask) + { + WARN( "Invalid alignment %lu.\n", r->Alignment ); + return STATUS_INVALID_PARAMETER; + } + align = r->Alignment; + } + limit = (ULONG_PTR)r->HighestEndingAddress; if (limit && (*ret || limit > (ULONG_PTR)user_space_limit || ((limit + 1) & (page_mask - 1)))) { WARN( "Invalid limit %p.\n", r->HighestEndingAddress); return STATUS_INVALID_PARAMETER; } - TRACE( "limit %p.\n", (void *)limit ); + TRACE( "limit %p, align %p.\n", (void *)limit, (void *)align ); } } @@ -3958,6 +3969,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s call.virtual_alloc_ex.addr = wine_server_client_ptr( *ret ); call.virtual_alloc_ex.size = *size_ptr; call.virtual_alloc_ex.limit = limit; + call.virtual_alloc_ex.align = align; call.virtual_alloc_ex.op_type = type; call.virtual_alloc_ex.prot = protect; status = server_queue_process_apc( process, &call, &result ); @@ -3971,7 +3983,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s return result.virtual_alloc_ex.status; } - return allocate_virtual_memory( ret, size_ptr, type, protect, limit ); + return allocate_virtual_memory( ret, size_ptr, type, protect, limit, align ); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 58dd870a6ce..472c0ea709d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -526,6 +526,7 @@ typedef union client_ptr_t addr; mem_size_t size; mem_size_t limit; + mem_size_t align; unsigned int prot; } virtual_alloc_ex; struct @@ -6355,7 +6356,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 757 +#define SERVER_PROTOCOL_VERSION 758 /* ### protocol_version end ### */ diff --git a/server/protocol.def b/server/protocol.def index 06977c29054..8c2fbeb4afe 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -542,6 +542,7 @@ typedef union client_ptr_t addr; /* requested address */ mem_size_t size; /* allocation size */ mem_size_t limit; /* allocation address limit */ + mem_size_t align; /* allocation alignment */ unsigned int prot; /* memory protection flags */ } virtual_alloc_ex; struct diff --git a/server/trace.c b/server/trace.c index 560a1b617ea..a0076d5449b 100644 --- a/server/trace.c +++ b/server/trace.c @@ -193,6 +193,7 @@ static void dump_apc_call( const char *prefix, const apc_call_t *call ) dump_uint64( "APC_VIRTUAL_ALLOC,addr==", &call->virtual_alloc_ex.addr ); dump_uint64( ",size=", &call->virtual_alloc_ex.size ); dump_uint64( ",limit=", &call->virtual_alloc_ex.limit ); + dump_uint64( ",align=", &call->virtual_alloc_ex.align ); fprintf( stderr, ",op_type=%x,prot=%x", call->virtual_alloc_ex.op_type, call->virtual_alloc_ex.prot ); break; case APC_VIRTUAL_FREE: