From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 72 ++++++++++++++++++++++++++++++++++++-- dlls/ntdll/unix/virtual.c | 56 +++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 45ba58868df..f5f1964e516 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -295,9 +295,9 @@ static void test_NtAllocateVirtualMemoryEx(void) { MEMORY_BASIC_INFORMATION mbi; MEM_EXTENDED_PARAMETER ext[2]; + char *p, *p1, *p2, *p3; void *addresses[16]; SIZE_T size, size2; - char *p, *p1, *p2; ULONG granularity; NTSTATUS status; ULONG_PTR count; @@ -510,6 +510,7 @@ static void test_NtAllocateVirtualMemoryEx(void)
p1 = addr1; p2 = p1 + size / 4; + p3 = p2 + size / 4; size2 = size / 4; status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); @@ -517,12 +518,79 @@ static void test_NtAllocateVirtualMemoryEx(void) ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2); ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1);
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + check_region_size(p1, p2 - p1); + check_region_size(p2, p3 - p2); + check_region_size(p3, size - (p3 - p1)); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_INVALID_PARAMETER_4, "Unexpected status %08lx.\n", status); + + size2 = size + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size - 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + p1 = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + p1 = addr1; + + size2 = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_INVALID_PARAMETER_3, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(size == 0x10000, "Unexpected size %#Ix.\n", size); + ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1); + check_region_size(p1, size); + + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2); + ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1); check_region_size(p1, size / 4); check_region_size(p2, size - size / 4); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + + size2 = size - size / 4; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), (void **)&p2, &size2, MEM_RESERVE | MEM_REPLACE_PLACEHOLDER, + PAGE_READWRITE, NULL, 0); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size - size / 4; status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(size2 == 0xc000, "Unexpected size %#Ix.\n", size2); + ok(p2 == p1 + size / 4, "Unexpected addr %p, expected %p.\n", p2, p1 + size / 4); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2); + ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1); + + size2 = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p3, &size2, MEM_RELEASE); + ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status);
/* Split in two regions, specifying second half. */ addr1 = NULL; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 6835f9cd645..d59315f7c78 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -114,6 +114,9 @@ struct file_view unsigned int protect; /* protection for all pages at allocation time and SEC_* flags */ };
+/* Assert this so RB_ENTRY_VALUE() result can be checked for NULL. */ +C_ASSERT( offsetof( struct file_view, entry ) == 0 ); + /* per-page protection flags */ #define VPROT_READ 0x01 #define VPROT_WRITE 0x02 @@ -2294,6 +2297,51 @@ static NTSTATUS free_pages( struct file_view *view, char *base, size_t size ) }
+/*********************************************************************** + * coalesce_placeholders + * + * Coalesce placeholder views. + * virtual_mutex must be held by caller. + */ +static NTSTATUS coalesce_placeholders( struct file_view *view, char *base, size_t size ) +{ + struct file_view *curr_view, *next_view; + unsigned int i, view_count = 0; + size_t views_size = 0; + + if (!size) return STATUS_INVALID_PARAMETER_3; + if (base != view->base) return STATUS_CONFLICTING_ADDRESSES; + + curr_view = view; + while (curr_view->protect & VPROT_FREE_PLACEHOLDER) + { + ++view_count; + views_size += curr_view->size; + if (views_size >= size) break; + if (!(next_view = RB_ENTRY_VALUE( rb_next( &curr_view->entry ), struct file_view, entry ))) break; + if ((char *)curr_view->base + curr_view->size != next_view->base) break; + curr_view = next_view; + } + + if (view_count < 2 || size != views_size) return STATUS_CONFLICTING_ADDRESSES; + + for (i = 1; i < view_count; ++i) + { + curr_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); + unregister_view( curr_view ); + free_view( curr_view ); + } + + unregister_view( view ); + view->size = views_size; + register_view( view ); + + VIRTUAL_DEBUG_DUMP_VIEW( view ); + + return STATUS_SUCCESS; +} + + /*********************************************************************** * allocate_dos_memory * @@ -4443,7 +4491,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; - else if ((char *)view->base + view->size - base < size) status = STATUS_UNABLE_TO_FREE_VM; + else if ((char *)view->base + view->size - base < size && !(type & MEM_COALESCE_PLACEHOLDERS)) + status = STATUS_UNABLE_TO_FREE_VM; else switch (type) { case MEM_DECOMMIT: @@ -4456,8 +4505,11 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si case MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER: status = free_pages_preserve_placeholder( view, base, size ); break; + case MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS: + status = coalesce_placeholders( view, base, size ); + break; default: - status = STATUS_INVALID_PARAMETER; + status = type & MEM_COALESCE_PLACEHOLDERS ? STATUS_INVALID_PARAMETER_4 : STATUS_INVALID_PARAMETER; break; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 70 +++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 29 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d59315f7c78..80df75234cd 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5215,11 +5215,13 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr alloc_type, protect, machine ); }
+ /*********************************************************************** - * NtUnmapViewOfSection (NTDLL.@) - * ZwUnmapViewOfSection (NTDLL.@) + * unmap_view_of_section + * + * NtUnmapViewOfSection[Ex] implementation. */ -NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) +static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) { struct file_view *view; unsigned int status = STATUS_NOT_MAPPED_VIEW; @@ -5240,42 +5242,52 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) }
server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if ((view = find_view( addr, 0 )) && !is_view_valloc( view )) + if (!(view = find_view( addr, 0 )) || is_view_valloc( view )) goto done; + + if (view->protect & VPROT_SYSTEM) { - if (view->protect & VPROT_SYSTEM) - { - struct builtin_module *builtin; + struct builtin_module *builtin;
- LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) + LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) + { + if (builtin->module != view->base) continue; + if (builtin->refcount > 1) { - if (builtin->module != view->base) continue; - if (builtin->refcount > 1) - { - TRACE( "not freeing in-use builtin %p\n", view->base ); - builtin->refcount--; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return STATUS_SUCCESS; - } + TRACE( "not freeing in-use builtin %p\n", view->base ); + builtin->refcount--; + server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + return STATUS_SUCCESS; } } + }
- SERVER_START_REQ( unmap_view ) - { - req->base = wine_server_client_ptr( view->base ); - status = wine_server_call( req ); - } - SERVER_END_REQ; - if (!status) - { - if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); - delete_view( view ); - } - else FIXME( "failed to unmap %p %x\n", view->base, status ); + SERVER_START_REQ( unmap_view ) + { + req->base = wine_server_client_ptr( view->base ); + status = wine_server_call( req ); } + SERVER_END_REQ; + if (!status) + { + if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); + delete_view( view ); + } + else FIXME( "failed to unmap %p %x\n", view->base, status ); +done: server_leave_uninterrupted_section( &virtual_mutex, &sigset ); return status; }
+ +/*********************************************************************** + * NtUnmapViewOfSection (NTDLL.@) + * ZwUnmapViewOfSection (NTDLL.@) + */ +NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) +{ + return unmap_view_of_section( process, addr ); +} + /*********************************************************************** * NtUnmapViewOfSectionEx (NTDLL.@) * ZwUnmapViewOfSectionEx (NTDLL.@) @@ -5283,7 +5295,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags ) { if (flags) FIXME("Ignoring flags %#x.\n", (int)flags); - return NtUnmapViewOfSection( process, addr ); + return unmap_view_of_section( process, addr ); }
/******************************************************************************
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/tests/process.c | 65 +++++++++++++++++++++++++++++++-- include/winnt.h | 1 + 2 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index e5185a2587d..7c6544f6dd9 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -41,6 +41,7 @@ static PVOID (WINAPI *pVirtualAllocFromApp)(PVOID, SIZE_T, DWORD, DWORD); static HANDLE (WINAPI *pOpenFileMappingFromApp)( ULONG, BOOL, LPCWSTR); static HANDLE (WINAPI *pCreateFileMappingFromApp)(HANDLE, PSECURITY_ATTRIBUTES, ULONG, ULONG64, PCWSTR); static LPVOID (WINAPI *pMapViewOfFileFromApp)(HANDLE, ULONG, ULONG64, SIZE_T); +static BOOL (WINAPI *pUnmapViewOfFile2)(HANDLE, void *, ULONG);
static void test_CompareObjectHandles(void) { @@ -166,6 +167,13 @@ static void test_VirtualAlloc2(void) ret = VirtualFree(addr, 0, MEM_RELEASE); ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError());
+ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE, PAGE_NOACCESS, NULL, 0); + ok(!!placeholder1, "Failed to create a placeholder range.\n"); + ret = VirtualFree(placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFree(placeholder1, 0, MEM_RELEASE); + ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError()); + /* Placeholder splitting functionality */ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); ok(!!placeholder1, "Failed to create a placeholder range.\n"); @@ -198,11 +206,20 @@ static void test_VirtualAlloc2(void) section = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL); ok(!!section, "Failed to create a section.\n");
- view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + view1 = pMapViewOfFile3(section, NULL, NULL, 0, size, 0, PAGE_READWRITE, NULL, 0); ok(!!view1, "Failed to map a section.\n"); + ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, 0); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + ok(view1 == placeholder1, "Address does not match.\n");
view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); - ok(!!view2, "Failed to map a section.\n"); + ok(view2 == placeholder2, "Address does not match.\n");
memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); @@ -218,8 +235,47 @@ static void test_VirtualAlloc2(void) ok(info.Type == MEM_MAPPED, "Unexpected type %#lx.\n", info.Type); ok(info.RegionSize == size, "Unexpected size.\n");
+ ret = pUnmapViewOfFile2(NULL, view1, MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got error %lu.\n", GetLastError()); + + ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + memset(&info, 0, sizeof(info)); + VirtualQuery(placeholder1, &info, sizeof(info)); + todo_wine ok(info.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", info.AllocationProtect); + todo_wine ok(info.State == MEM_RESERVE, "Unexpected state %#lx.\n", info.State); + todo_wine ok(info.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", info.Type); + ok(info.RegionSize == size, "Unexpected size.\n"); + + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError()); + + ret = UnmapViewOfFile(view1); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError()); + + view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + todo_wine ok(view1 == placeholder1, "Address does not match.\n"); CloseHandle(section); - UnmapViewOfFile(view1); + + ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_UNMAP_WITH_TRANSIENT_BOOST | MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFreeEx(GetCurrentProcess(), placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFree(placeholder1, 0, MEM_RELEASE); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + UnmapViewOfFile(view2);
VirtualFree(placeholder1, 0, MEM_RELEASE); @@ -249,6 +305,8 @@ static void test_VirtualAlloc2(void)
p1 = p; p2 = p + size / 2; + ret = VirtualFree(p1, 0, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = VirtualFree(p1, size / 2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); ok(ret, "Failed to split a placeholder.\n"); check_region_size(p1, size / 2); @@ -461,6 +519,7 @@ static void init_funcs(void) X(VirtualAlloc2); X(VirtualAlloc2FromApp); X(VirtualAllocFromApp); + X(UnmapViewOfFile2);
hmod = GetModuleHandleA("ntdll.dll");
diff --git a/include/winnt.h b/include/winnt.h index 66746d7f6ae..19349a73709 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -837,6 +837,7 @@ typedef struct DECLSPEC_ALIGN(8) MEM_EXTENDED_PARAMETER { #define MEM_PRESERVE_PLACEHOLDER 0x00000002 #define MEM_DECOMMIT 0x00004000 #define MEM_RELEASE 0x00008000 +#define MEM_UNMAP_WITH_TRANSIENT_BOOST 0x00000001
#define MEM_FREE 0x00010000 #define MEM_PRIVATE 0x00020000
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/tests/process.c | 4 ++-- dlls/ntdll/unix/virtual.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index 7c6544f6dd9..2e5bb7ca458 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -242,9 +242,9 @@ static void test_VirtualAlloc2(void) ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError());
ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - todo_wine ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 80df75234cd..0396b49b60f 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5294,7 +5294,14 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) */ NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags ) { - if (flags) FIXME("Ignoring flags %#x.\n", (int)flags); + static const ULONG type_mask = MEM_UNMAP_WITH_TRANSIENT_BOOST | MEM_PRESERVE_PLACEHOLDER; + + if (flags & ~type_mask) + { + WARN( "Unsupported flags %#x.\n", (int)flags ); + return STATUS_INVALID_PARAMETER; + } + if (flags) FIXME( "Ignoring flags %#x.\n", (int)flags ); return unmap_view_of_section( process, addr ); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/tests/process.c | 16 ++++++++-------- dlls/ntdll/unix/server.c | 2 +- dlls/ntdll/unix/virtual.c | 17 ++++++++++++----- server/protocol.def | 1 + 4 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index 2e5bb7ca458..88a527c45d5 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -211,9 +211,9 @@ static void test_VirtualAlloc2(void) ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); - todo_wine ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, 0); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); ok(view1 == placeholder1, "Address does not match.\n"); @@ -248,9 +248,9 @@ static void test_VirtualAlloc2(void)
memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); - todo_wine ok(info.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", info.AllocationProtect); - todo_wine ok(info.State == MEM_RESERVE, "Unexpected state %#lx.\n", info.State); - todo_wine ok(info.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", info.Type); + ok(info.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", info.AllocationProtect); + ok(info.State == MEM_RESERVE, "Unexpected state %#lx.\n", info.State); + ok(info.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", info.Type); ok(info.RegionSize == size, "Unexpected size.\n");
ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); @@ -260,21 +260,21 @@ static void test_VirtualAlloc2(void) ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError());
view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); - todo_wine ok(view1 == placeholder1, "Address does not match.\n"); + ok(view1 == placeholder1, "Address does not match.\n"); CloseHandle(section);
ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError());
ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_UNMAP_WITH_TRANSIENT_BOOST | MEM_PRESERVE_PLACEHOLDER); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = VirtualFreeEx(GetCurrentProcess(), placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = VirtualFree(placeholder1, 0, MEM_RELEASE); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
UnmapViewOfFile(view2);
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 53deff744ba..227784448d3 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -615,7 +615,7 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO result->type = call->type; addr = wine_server_get_ptr( call->unmap_view.addr ); if ((ULONG_PTR)addr == call->unmap_view.addr) - result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr ); + result->unmap_view.status = NtUnmapViewOfSectionEx( NtCurrentProcess(), addr, call->unmap_view.flags ); else result->unmap_view.status = STATUS_INVALID_PARAMETER; break; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 0396b49b60f..b4d8a2bf269 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5221,7 +5221,7 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr * * NtUnmapViewOfSection[Ex] implementation. */ -static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) +static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) { struct file_view *view; unsigned int status = STATUS_NOT_MAPPED_VIEW; @@ -5236,6 +5236,7 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
call.unmap_view.type = APC_UNMAP_VIEW; call.unmap_view.addr = wine_server_client_ptr( addr ); + call.unmap_view.flags = flags; status = server_queue_process_apc( process, &call, &result ); if (status == STATUS_SUCCESS) status = result.unmap_view.status; return status; @@ -5244,6 +5245,11 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) server_enter_uninterrupted_section( &virtual_mutex, &sigset ); if (!(view = find_view( addr, 0 )) || is_view_valloc( view )) goto done;
+ if (flags & MEM_PRESERVE_PLACEHOLDER && !(view->protect & VPROT_PLACEHOLDER)) + { + status = STATUS_CONFLICTING_ADDRESSES; + goto done; + } if (view->protect & VPROT_SYSTEM) { struct builtin_module *builtin; @@ -5270,7 +5276,8 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) if (!status) { if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); - delete_view( view ); + if (flags & MEM_PRESERVE_PLACEHOLDER) free_pages_preserve_placeholder( view, view->base, view->size ); + else delete_view( view ); } else FIXME( "failed to unmap %p %x\n", view->base, status ); done: @@ -5285,7 +5292,7 @@ done: */ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) { - return unmap_view_of_section( process, addr ); + return unmap_view_of_section( process, addr, 0 ); }
/*********************************************************************** @@ -5301,8 +5308,8 @@ NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags WARN( "Unsupported flags %#x.\n", (int)flags ); return STATUS_INVALID_PARAMETER; } - if (flags) FIXME( "Ignoring flags %#x.\n", (int)flags ); - return unmap_view_of_section( process, addr ); + if (flags & MEM_UNMAP_WITH_TRANSIENT_BOOST) FIXME( "Ignoring MEM_UNMAP_WITH_TRANSIENT_BOOST.\n" ); + return unmap_view_of_section( process, addr, flags ); }
/****************************************************************************** diff --git a/server/protocol.def b/server/protocol.def index 95ddb1d5011..70948c32f30 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -616,6 +616,7 @@ typedef union enum apc_type type; /* APC_UNMAP_VIEW */ int __pad; client_ptr_t addr; /* view address */ + unsigned int flags; /* unmap flags */ } unmap_view; struct {
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=133097
Your paranoid android.
=== debian11 (32 bit report) ===
user32: msg.c:6897: Test failed: SetFocus(hwnd) on a button: 4: the msg 0x0007 was expected, but got msg 0x0005 instead msg.c:6897: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0138 was expected, but got msg 0x030f instead msg.c:6897: Test failed: SetFocus(hwnd) on a button: 6: the msg 0x0111 was expected, but got msg 0x001c instead msg.c:6897: Test failed: SetFocus(hwnd) on a button: 8: the msg 0x8000 was expected, but got msg 0x0086 instead msg.c:6897: Test failed: SetFocus(hwnd) on a button: 9: the msg sequence is not complete: expected 0000 - actual 0006