Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/kernel32/tests/process.c | 2 +- include/winternl.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index c1312bd8916..4a6451a23fe 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3773,7 +3773,7 @@ static void test_process_info(HANDLE hproc) return; }
- for (i = 0; i < MaxProcessInfoClass; i++) + for (i = 0; i < ARRAY_SIZE(info_size); i++) { ret_len = 0; status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len); diff --git a/include/winternl.h b/include/winternl.h index ca265cf074c..c992eaebf11 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1566,6 +1566,14 @@ typedef enum _PROCESSINFOCLASS { ProcessThreadStackAllocation = 41, ProcessWorkingSetWatchEx = 42, ProcessImageFileNameWin32 = 43, + ProcessImageFileMapping = 44, + ProcessAffinityUpdateMode = 45, + ProcessMemoryAllocationMode = 46, + ProcessGroupInformation = 47, + ProcessTokenVirtualizationEnabled = 48, + ProcessConsoleHostProcess = 49, + ProcessWindowInformation = 50, + ProcessHandleInformation = 51, MaxProcessInfoClass, #ifdef __WINESRC__ ProcessWineMakeProcessSystem = 1000,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/tests/info.c | 33 +++++++++++++++++++++++ dlls/ntdll/unix/process.c | 49 ++++++++++++++++++++++++++++++++++ dlls/wow64/process.c | 40 +++++++++++++++++++++++++++ dlls/wow64/struct32.h | 18 +++++++++++++ include/wine/server_protocol.h | 20 +++++++++++++- include/winternl.h | 18 +++++++++++++ server/handle.c | 31 +++++++++++++++++++++ server/protocol.def | 9 +++++++ server/request.h | 6 +++++ server/trace.c | 14 ++++++++++ 10 files changed, 237 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 89503093b17..dc141c6bf9c 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -2559,6 +2559,38 @@ static void test_query_process_debug_flags(int argc, char **argv) } }
+static void test_query_process_handles(void) +{ + PROCESS_HANDLE_SNAPSHOT_INFORMATION *snapshot; + ULONG ret_length, length; + NTSTATUS status; + unsigned int i; + + ret_length = 0; + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, NULL, 0, &ret_length); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status); + + length = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[1]); + snapshot = malloc(length); + ret_length = 0; + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, snapshot, length, &ret_length); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status); + ok(ret_length, "Unexpected length %lu.\n", ret_length); + free(snapshot); + + snapshot = malloc(ret_length); + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, snapshot, ret_length, &ret_length); + ok(status == STATUS_SUCCESS, "Unexpected status %#lx.\n", status); + ok(ret_length, "Unexpected return length.\n"); + ok(snapshot->NumberOfHandles, "Unexpected handle count.\n"); + for (i = 0; i < min(3, snapshot->NumberOfHandles); ++i) + { + PROCESS_HANDLE_TABLE_ENTRY_INFO *ptr = &snapshot->Handles[i]; + ok(!!ptr->HandleValue, "Unexpected handle.\n"); + } + free(snapshot); +} + static void test_readvirtualmemory(void) { HANDLE process; @@ -3588,6 +3620,7 @@ START_TEST(info) test_query_process_debug_object_handle(argc, argv); test_query_process_debug_flags(argc, argv); test_query_process_image_info(); + test_query_process_handles(); test_mapprotection(); test_threadstack();
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 078ad75099d..649a26be8e4 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1094,6 +1094,13 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled); UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination); UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing); + UNIMPLEMENTED_INFO_CLASS(ProcessImageFileMapping); + UNIMPLEMENTED_INFO_CLASS(ProcessAffinityUpdateMode); + UNIMPLEMENTED_INFO_CLASS(ProcessMemoryAllocationMode); + UNIMPLEMENTED_INFO_CLASS(ProcessGroupInformation); + UNIMPLEMENTED_INFO_CLASS(ProcessTokenVirtualizationEnabled); + UNIMPLEMENTED_INFO_CLASS(ProcessConsoleHostProcess); + UNIMPLEMENTED_INFO_CLASS(ProcessWindowInformation);
case ProcessBasicInformation: { @@ -1496,6 +1503,48 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class else ret = STATUS_INFO_LENGTH_MISMATCH; break;
+ case ProcessHandleInformation: + if (size >= sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION)) + { + struct handle_info *handle_info; + unsigned int i, num_handles; + + num_handles = (size - FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles )) / sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO); + if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY; + + SERVER_START_REQ(get_process_handle_info) + { + req->handle = wine_server_obj_handle( handle ); + wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles ); + if (!(ret = wine_server_call( req ))) + { + PROCESS_HANDLE_SNAPSHOT_INFORMATION *snapshot = info; + snapshot->NumberOfHandles = reply->handle_count; + snapshot->Reserved = 0; + for (i = 0; i < snapshot->NumberOfHandles; i++) + { + PROCESS_HANDLE_TABLE_ENTRY_INFO *entry = &snapshot->Handles[i]; + memset( entry, 0, sizeof(*entry) ); + entry->HandleValue = handle_info[i].handle; + entry->GrantedAccess = handle_info[i].access; + entry->HandleAttributes = handle_info[i].attributes; + /* FIXME: Fill out remaining fields */ + } + len = FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[reply->handle_count] ); + } + else if (ret == STATUS_BUFFER_TOO_SMALL) + { + len = FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[reply->handle_count] ); + ret = STATUS_INFO_LENGTH_MISMATCH; + } + } + SERVER_END_REQ; + + free(handle_info); + } + else ret = STATUS_INFO_LENGTH_MISMATCH; + break; + default: FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n", handle, class, info, size, ret_len ); diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 82ca4181116..a62d6073752 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -847,6 +847,46 @@ NTSTATUS WINAPI wow64_NtQueryInformationProcess( UINT *args ) if (retlen) *retlen = sizeof(SECTION_IMAGE_INFORMATION32); return STATUS_INFO_LENGTH_MISMATCH;
+ case ProcessHandleInformation: + if (len >= sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION32)) + { + PROCESS_HANDLE_SNAPSHOT_INFORMATION *info = NULL; + PROCESS_HANDLE_SNAPSHOT_INFORMATION32 *info32 = ptr; + ULONG size = 0, retsize = 0, count, i; + + if (ptr) + { + size = info32->NumberOfHandles * FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[info->NumberOfHandles]); + info = Wow64AllocateTemp( size ); + } + + if (!(status = NtQueryInformationProcess( handle, class, info, size, &retsize ))) + { + info32->NumberOfHandles = info->NumberOfHandles; + for (i = 0; i < info->NumberOfHandles; ++i) + { + PROCESS_HANDLE_TABLE_ENTRY_INFO32 *entry32 = &info32->Handles[i]; + const PROCESS_HANDLE_TABLE_ENTRY_INFO *entry = &info->Handles[i]; + + entry32->HandleValue = entry->HandleValue; + entry32->HandleCount = entry->HandleCount; + entry32->PointerCount = entry->PointerCount; + entry32->GrantedAccess = entry->GrantedAccess; + entry32->ObjectTypeIndex = entry->ObjectTypeIndex; + entry32->HandleAttributes = entry->HandleAttributes; + } + if (retlen) *retlen = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION32, Handles[info->NumberOfHandles]); + } + else if (status == STATUS_INFO_LENGTH_MISMATCH) + { + count = (retsize - FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles)) / sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO); + if (retlen) *retlen = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION32, Handles[count]); + } + return status; + } + if (retlen) *retlen = sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION32); + return STATUS_INFO_LENGTH_MISMATCH; + default: FIXME( "unsupported class %u\n", class ); return STATUS_INVALID_INFO_CLASS; diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index b096c8d587b..466ff38582d 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -650,6 +650,24 @@ typedef struct ULONG Reserved4; } SYSTEM_EXTENDED_THREAD_INFORMATION32;
+typedef struct +{ + ULONG HandleValue; + ULONG HandleCount; + ULONG PointerCount; + ULONG GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO32; + +typedef struct +{ + ULONG NumberOfHandles; + ULONG Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO32 Handles[1]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION32; + struct __server_iovec32 { ULONG ptr; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 868add58abf..fed5ecb8aad 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5445,6 +5445,21 @@ struct get_next_thread_reply };
+ +struct get_process_handle_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_process_handle_info_reply +{ + struct reply_header __header; + unsigned int handle_count; + /* VARARG(data,handle_infos); */ + char __pad_12[4]; +}; + + enum request { REQ_new_process, @@ -5722,6 +5737,7 @@ enum request REQ_suspend_process, REQ_resume_process, REQ_get_next_thread, + REQ_get_process_handle_info, REQ_NB_REQUESTS };
@@ -6004,6 +6020,7 @@ union generic_request struct suspend_process_request suspend_process_request; struct resume_process_request resume_process_request; struct get_next_thread_request get_next_thread_request; + struct get_process_handle_info_request get_process_handle_info_request; }; union generic_reply { @@ -6284,11 +6301,12 @@ union generic_reply struct suspend_process_reply suspend_process_reply; struct resume_process_reply resume_process_reply; struct get_next_thread_reply get_next_thread_reply; + struct get_process_handle_info_reply get_process_handle_info_reply; };
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 751 +#define SERVER_PROTOCOL_VERSION 752
/* ### protocol_version end ### */
diff --git a/include/winternl.h b/include/winternl.h index c992eaebf11..62874b3ebbe 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2244,6 +2244,24 @@ typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo; } PROCESS_STACK_ALLOCATION_INFORMATION_EX, *PPROCESS_STACK_ALLOCATION_INFORMATION_EX;
+typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO +{ + ULONG_PTR HandleValue; + ULONG_PTR HandleCount; + ULONG_PTR PointerCount; + ULONG GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION; + typedef struct _RTL_HEAP_DEFINITION { ULONG Length; /* = sizeof(RTL_HEAP_DEFINITION) */
diff --git a/server/handle.c b/server/handle.c index 38ad80da267..89de2741f37 100644 --- a/server/handle.c +++ b/server/handle.c @@ -866,6 +866,37 @@ DECL_HANDLER(get_system_handles) } }
+/* Get a process handle snapshot */ +DECL_HANDLER(get_process_handle_info) +{ + struct enum_handle_info info; + struct handle_info *handle; + struct process *process; + data_size_t max_handles; + + max_handles = get_reply_max_size() / sizeof(*handle); + if (!(process = get_process_from_handle( req->handle, max_handles ? PROCESS_DUP_HANDLE : PROCESS_QUERY_INFORMATION ))) + return; + + info.handle = NULL; + info.count = 0; + enum_handles( process, &info ); + reply->handle_count = info.count; + + if (max_handles) + { + if (max_handles < info.count) + set_error( STATUS_BUFFER_TOO_SMALL ); + else if ((handle = set_reply_data_size( info.count * sizeof(*handle) ))) + { + info.handle = handle; + enum_handles( process, &info ); + } + } + + release_object( process ); +} + DECL_HANDLER(make_temporary) { struct object *obj; diff --git a/server/protocol.def b/server/protocol.def index 2be1658fca2..b4050c52b02 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3747,3 +3747,12 @@ struct handle_info @REPLY obj_handle_t handle; /* next thread handle */ @END + + +/* Get a process handles snapshot */ +@REQ(get_process_handle_info) + obj_handle_t handle; /* process handle */ +@REPLY + unsigned int handle_count; /* count of process handles */ + VARARG(data,handle_infos); /* handle information */ +@END diff --git a/server/request.h b/server/request.h index 7fd63905e0e..ca2c835b232 100644 --- a/server/request.h +++ b/server/request.h @@ -394,6 +394,7 @@ DECL_HANDLER(terminate_job); DECL_HANDLER(suspend_process); DECL_HANDLER(resume_process); DECL_HANDLER(get_next_thread); +DECL_HANDLER(get_process_handle_info);
#ifdef WANT_REQUEST_HANDLERS
@@ -675,6 +676,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_suspend_process, (req_handler)req_resume_process, (req_handler)req_get_next_thread, + (req_handler)req_get_process_handle_info, };
C_ASSERT( sizeof(abstime_t) == 8 ); @@ -2255,6 +2257,10 @@ C_ASSERT( FIELD_OFFSET(struct get_next_thread_request, flags) == 28 ); C_ASSERT( sizeof(struct get_next_thread_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_next_thread_reply, handle) == 8 ); C_ASSERT( sizeof(struct get_next_thread_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_process_handle_info_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_process_handle_info_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_process_handle_info_reply, handle_count) == 8 ); +C_ASSERT( sizeof(struct get_process_handle_info_reply) == 16 );
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/trace.c b/server/trace.c index 15ca4e7d71e..4c9a6e9de22 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4486,6 +4486,17 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req fprintf( stderr, " handle=%04x", req->handle ); }
+static void dump_get_process_handle_info_request( const struct get_process_handle_info_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_process_handle_info_reply( const struct get_process_handle_info_reply *req ) +{ + fprintf( stderr, " handle_count=%08x", req->handle_count ); + dump_varargs_handle_infos( ", data=", cur_size ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -4762,6 +4773,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_suspend_process_request, (dump_func)dump_resume_process_request, (dump_func)dump_get_next_thread_request, + (dump_func)dump_get_process_handle_info_request, };
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -5040,6 +5052,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, (dump_func)dump_get_next_thread_reply, + (dump_func)dump_get_process_handle_info_reply, };
static const char * const req_names[REQ_NB_REQUESTS] = { @@ -5318,6 +5331,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "suspend_process", "resume_process", "get_next_thread", + "get_process_handle_info", };
static const struct
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=115281
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
ntdll: info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected length 0. info.c:2583: Test failed: Unexpected status 0xc0000003. info.c:2584: Test failed: Unexpected return length.
=== w7u_adm (32 bit report) ===
ntdll: info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected length 0. info.c:2583: Test failed: Unexpected status 0xc0000003. info.c:2584: Test failed: Unexpected return length.
=== w7u_el (32 bit report) ===
ntdll: info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected length 0. info.c:2583: Test failed: Unexpected status 0xc0000003. info.c:2584: Test failed: Unexpected return length.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/tests/info.c | 8 +------- dlls/ntdll/unix/process.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index dc141c6bf9c..67040d2263d 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -2222,13 +2222,7 @@ static void test_query_process_handlecount(void) ok( status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_SUCCESS, "Expected STATUS_INFO_LENGTH_MISMATCH or STATUS_SUCCESS, got %08lx\n", status); ok( sizeof(handlecount) == ReturnLength, "Inconsistent length %ld\n", ReturnLength); - - /* Check if we have some return values */ - if (winetest_debug > 1) trace("HandleCount : %ld\n", handlecount); - todo_wine - { - ok( handlecount > 0, "Expected some handles, got 0\n"); - } + ok( handlecount > 0, "Expected some handles, got 0\n"); }
static void test_query_process_image_file_name(void) diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 649a26be8e4..886aa2cfead 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1349,11 +1349,16 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class if (size >= 4) { if (!info) ret = STATUS_ACCESS_VIOLATION; - else if (!handle) ret = STATUS_INVALID_HANDLE; else { - memset(info, 0, 4); - len = 4; + SERVER_START_REQ(get_process_handle_info) + { + req->handle = wine_server_obj_handle( handle ); + ret = wine_server_call( req ); + *(ULONG *)info = reply->handle_count; + } + SERVER_END_REQ; + if (ret == STATUS_SUCCESS) len = 4; } if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=115282
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
ntdll: info.c:2565: Test failed: Unexpected status 0xc0000003. info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2572: Test failed: Unexpected length 0. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected return length.
=== w7u_adm (32 bit report) ===
ntdll: info.c:2565: Test failed: Unexpected status 0xc0000003. info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2572: Test failed: Unexpected length 0. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected return length.
=== w7u_el (32 bit report) ===
ntdll: info.c:2565: Test failed: Unexpected status 0xc0000003. info.c:2571: Test failed: Unexpected status 0xc0000003. info.c:2572: Test failed: Unexpected length 0. info.c:2577: Test failed: Unexpected status 0xc0000003. info.c:2578: Test failed: Unexpected return length.