diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index d03ee7bb075..3c64a068a2a 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -103,22 +103,17 @@ static void test_VirtualAllocEx(void) /* test a not committed memory */ memset(&info, 'q', sizeof(info)); - todo_wine ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) - == sizeof(info), "VirtualQueryEx failed\n"); - todo_wine ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, - addr1); - todo_wine ok(info.AllocationBase == addr1, "%p != %p\n", - info.AllocationBase, addr1); - todo_wine ok(info.AllocationProtect == PAGE_NOACCESS, - "%x != PAGE_NOACCESS\n", info.AllocationProtect); - todo_wine ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", - info.RegionSize); - todo_wine ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); + ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); /* NT reports Protect == 0 for a not committed memory block */ - todo_wine ok(info.Protect == 0 /* NT */ || + ok(info.Protect == 0 /* NT */ || info.Protect == PAGE_NOACCESS, /* Win9x */ "%x != PAGE_NOACCESS\n", info.Protect); - todo_wine ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); SetLastError(0xdeadbeef); ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot), @@ -131,20 +126,16 @@ static void test_VirtualAllocEx(void) ok(addr1 == addr2, "VirtualAllocEx failed\n"); /* test a committed memory */ - todo_wine ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) - == sizeof(info), + ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n"); - todo_wine ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, - addr1); - todo_wine ok(info.AllocationBase == addr1, "%p != %p\n", - info.AllocationBase, addr1); - todo_wine ok(info.AllocationProtect == PAGE_NOACCESS, - "%x != PAGE_NOACCESS\n", info.AllocationProtect); - todo_wine ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); - todo_wine ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); /* this time NT reports PAGE_NOACCESS as well */ - todo_wine ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect); - todo_wine ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); /* this should fail, since not the whole range is committed yet */ SetLastError(0xdeadbeef); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 70dc4c9779c..e0eb2d4645b 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -726,6 +726,26 @@ static BOOL call_apcs( BOOL alertable ) &result.virtual_free.size, call.virtual_free.op_type ); break; + case APC_VIRTUAL_QUERY: + { + MEMORY_BASIC_INFORMATION info; + result.type = call.type; + result.virtual_query.status = NtQueryVirtualMemory( NtCurrentProcess(), + call.virtual_query.addr, + MemoryBasicInformation, &info, + sizeof(info), NULL ); + if (result.virtual_query.status == STATUS_SUCCESS) + { + result.virtual_query.base = info.BaseAddress; + result.virtual_query.alloc_base = info.AllocationBase; + result.virtual_query.size = info.RegionSize; + result.virtual_query.state = info.State; + result.virtual_query.prot = info.Protect; + result.virtual_query.alloc_prot = info.AllocationProtect; + result.virtual_query.alloc_type = info.Type; + } + break; + } default: server_protocol_error( "get_apc_request: bad type %d\n", call.type ); break; diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 9c613ccc4cc..0407a213078 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1682,10 +1682,29 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT) return STATUS_WORKING_SET_LIMIT_RANGE; - if (!is_current_process( process )) + if (process != NtCurrentProcess()) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + NTSTATUS status; + apc_call_t call; + apc_result_t result; + + call.virtual_query.type = APC_VIRTUAL_QUERY; + call.virtual_query.addr = addr; + status = NTDLL_queue_process_apc( process, &call, &result ); + if (status != STATUS_SUCCESS) return status; + + if (result.virtual_query.status == STATUS_SUCCESS) + { + info->BaseAddress = result.virtual_query.base; + info->AllocationBase = result.virtual_query.alloc_base; + info->RegionSize = result.virtual_query.size; + info->State = result.virtual_query.state; + info->Protect = result.virtual_query.prot; + info->AllocationProtect = result.virtual_query.alloc_prot; + info->Type = result.virtual_query.alloc_type; + if (res_len) *res_len = sizeof(*info); + } + return result.virtual_query.status; } base = ROUND_ADDR( addr, page_mask ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 988b3c785de..60715ff0d5c 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -216,7 +216,8 @@ enum apc_type APC_TIMER, APC_ASYNC_IO, APC_VIRTUAL_ALLOC, - APC_VIRTUAL_FREE + APC_VIRTUAL_FREE, + APC_VIRTUAL_QUERY }; typedef union @@ -259,6 +260,11 @@ typedef union unsigned long size; unsigned int op_type; } virtual_free; + struct + { + enum apc_type type; + const void *addr; + } virtual_query; } apc_call_t; typedef union @@ -278,6 +284,18 @@ typedef union void *addr; unsigned long size; } virtual_free; + struct + { + enum apc_type type; + unsigned int status; + void *base; + void *alloc_base; + unsigned long size; + unsigned int state; + unsigned int prot; + unsigned int alloc_prot; + unsigned int alloc_type; + } virtual_query; } apc_result_t; @@ -4499,6 +4517,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 266 +#define SERVER_PROTOCOL_VERSION 267 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 5ac0001cefb..b24e27546f0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -232,7 +232,8 @@ enum apc_type APC_TIMER, APC_ASYNC_IO, APC_VIRTUAL_ALLOC, - APC_VIRTUAL_FREE + APC_VIRTUAL_FREE, + APC_VIRTUAL_QUERY }; typedef union @@ -275,6 +276,11 @@ typedef union unsigned long size; /* allocation size */ unsigned int op_type; /* type of operation */ } virtual_free; + struct + { + enum apc_type type; /* APC_VIRTUAL_QUERY */ + const void *addr; /* requested address */ + } virtual_query; } apc_call_t; typedef union @@ -294,6 +300,18 @@ typedef union void *addr; /* resulting address */ unsigned long size; /* resulting size */ } virtual_free; + struct + { + enum apc_type type; /* APC_VIRTUAL_QUERY */ + unsigned int status; /* status returned by call */ + void *base; /* resulting base address */ + void *alloc_base;/* resulting allocation base */ + unsigned long size; /* resulting region size */ + unsigned int state; /* resulting region state */ + unsigned int prot; /* resulting region protection */ + unsigned int alloc_prot;/* resulting allocation protection */ + unsigned int alloc_type;/* resulting region allocation type */ + } virtual_query; } apc_result_t; /****************************************************************/ diff --git a/server/thread.c b/server/thread.c index f99f76336d0..62bd559f596 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1140,6 +1140,7 @@ DECL_HANDLER(queue_apc) struct thread *thread; struct process *process; struct thread_apc *apc; + unsigned int access; if (!(apc = create_apc( NULL, &req->call ))) return; @@ -1155,7 +1156,9 @@ DECL_HANDLER(queue_apc) break; case APC_VIRTUAL_ALLOC: case APC_VIRTUAL_FREE: - if ((process = get_process_from_handle( req->process, PROCESS_VM_OPERATION ))) + case APC_VIRTUAL_QUERY: + access = (apc->call.type == APC_VIRTUAL_QUERY) ? PROCESS_QUERY_INFORMATION : PROCESS_VM_OPERATION; + if ((process = get_process_from_handle( req->process, access ))) { obj_handle_t handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 ); if (handle) diff --git a/server/trace.c b/server/trace.c index 6e4f7457e96..2b9ee8caf84 100644 --- a/server/trace.c +++ b/server/trace.c @@ -130,6 +130,9 @@ static void dump_apc_call( const apc_call_t *call ) call->virtual_free.addr, call->virtual_free.size, call->virtual_free.op_type ); break; + case APC_VIRTUAL_QUERY: + fprintf( stderr, "APC_VIRTUAL_QUERY,addr=%p", call->virtual_query.addr ); + break; default: fprintf( stderr, "type=%u", call->type ); break; @@ -154,6 +157,14 @@ static void dump_apc_result( const apc_result_t *result ) get_status_name( result->virtual_free.status ), result->virtual_free.addr, result->virtual_free.size ); break; + case APC_VIRTUAL_QUERY: + fprintf( stderr, "APC_VIRTUAL_QUERY,status=%s,base=%p,alloc_base=%p,size=%lu,state=%x,prot=%x,alloc_prot=%x,alloc_type=%x", + get_status_name( result->virtual_query.status ), + result->virtual_query.base, result->virtual_query.alloc_base, + result->virtual_query.size, result->virtual_query.state, + result->virtual_query.prot, result->virtual_query.alloc_prot, + result->virtual_query.alloc_type ); + break; default: fprintf( stderr, "type=%u", result->type ); break;