From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 42 ++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/server.c | 7 +++++-- dlls/ntdll/unix/virtual.c | 24 ++++++++++++++++------ server/protocol.def | 1 + server/trace.c | 1 + 5 files changed, 67 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 24a621b5136..1a476ac8f20 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 fbb5458fc23..f42cde2c894 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3730,7 +3730,7 @@ void virtual_set_large_address_space(void) * NtAllocateVirtualMempory[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; @@ -3792,7 +3792,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; } @@ -3880,7 +3880,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 ); }
@@ -3893,6 +3893,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 );
@@ -3924,17 +3925,27 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s mem_requirements_found = 1; 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 ); } }
@@ -3952,6 +3963,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 ); @@ -3965,7 +3977,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/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: