Should help with Overwatch 2 random crashes after some time of playing.
-- v2: ntdll: Implement NtQuerySystemInformation( SystemProcessIdInformation ).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/info.c | 129 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/system.c | 39 ++++++++++++ dlls/wow64/struct32.h | 6 ++ dlls/wow64/system.c | 18 ++++++ include/winternl.h | 6 ++ server/process.c | 5 +- server/protocol.def | 1 + 7 files changed, 203 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index ce5475df763..88086a83f59 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -28,6 +28,7 @@ #include "winternl.h" #include "winnls.h" #include "ddk/ntddk.h" +#include "psapi.h" #include "wine/test.h"
static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); @@ -3892,6 +3893,133 @@ static void test_process_token(int argc, char **argv) CloseHandle( token ); }
+static void test_process_id(void) +{ + char image_name_buffer[1024 * sizeof(WCHAR)]; + UNICODE_STRING *image_name = (UNICODE_STRING *)image_name_buffer; + SYSTEM_PROCESS_ID_INFORMATION info; + unsigned int i, length; + DWORD pids[2048]; + WCHAR name[2048]; + NTSTATUS status; + HANDLE process; + ULONG len; + BOOL bret; + + status = NtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, image_name, + sizeof(image_name_buffer), NULL ); + ok( !status, "got %#lx.\n", status ); + length = image_name->Length; + image_name->Buffer[length] = 0; + + len = 0xdeadbeef; + status = pNtQuerySystemInformation( SystemProcessIdInformation, NULL, 0, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH || (is_wow64 && status == STATUS_ACCESS_VIOLATION), "got %#lx.\n", status ); + ok( len == sizeof(info) || (is_wow64 && len == 0xdeadbeef), "got %#lx.\n", len ); + + info.ProcessId = 0xdeadbeef; + info.ImageName.Length = info.ImageName.MaximumLength = 0; + info.ImageName.Buffer = NULL; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INVALID_CID, "got %#lx.\n", status ); + ok( !info.ImageName.Length, "got %#x.\n", info.ImageName.Length ); + ok( !info.ImageName.MaximumLength, "got %#x.\n", info.ImageName.MaximumLength ); + + info.ProcessId = GetCurrentProcessId(); + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status ); + ok( len == sizeof(info), "got %#lx.\n", len ); + ok( !info.ImageName.Length, "got %#x.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == length + 2 || (is_wow64 && !info.ImageName.MaximumLength), + "got %#x.\n", info.ImageName.MaximumLength ); + + info.ImageName.MaximumLength = sizeof(name); + len = 0xdeadbeef; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status ); + ok( len == sizeof(info), "got %#lx.\n", len ); + ok( info.ImageName.Length == length || (is_wow64 && !info.ImageName.Length), + "got %u.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == length + 2 || (is_wow64 && !info.ImageName.Length), + "got %#x.\n", info.ImageName.MaximumLength ); + + info.ProcessId = 0xdeadbeef; + info.ImageName.MaximumLength = sizeof(name); + info.ImageName.Buffer = name; + info.ImageName.Length = 0; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INVALID_CID, "got %#lx.\n", status ); + ok( !info.ImageName.Length, "got %#x.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == sizeof(name), "got %#x.\n", info.ImageName.MaximumLength ); + ok( info.ImageName.Buffer == name, "got %p, %p.\n", info.ImageName.Buffer, name ); + + info.ProcessId = 0; + info.ImageName.MaximumLength = sizeof(name); + info.ImageName.Buffer = name; + info.ImageName.Length = 0; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INVALID_CID, "got %#lx.\n", status ); + ok( !info.ImageName.Length, "got %#x.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == sizeof(name), "got %#x.\n", info.ImageName.MaximumLength ); + ok( info.ImageName.Buffer == name, "got non NULL.\n" ); + + info.ProcessId = 0; + info.ImageName.MaximumLength = sizeof(name); + info.ImageName.Buffer = name; + info.ImageName.Length = 4; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status ); + ok( info.ImageName.Length == 4, "got %#x.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == sizeof(name), "got %#x.\n", info.ImageName.MaximumLength ); + ok( info.ImageName.Buffer == name, "got non NULL.\n" ); + + info.ProcessId = GetCurrentProcessId(); + info.ImageName.MaximumLength = sizeof(name); + info.ImageName.Buffer = name; + info.ImageName.Length = 4; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), NULL ); + ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status ); + ok( info.ImageName.Length == 4, "got %#x.\n", info.ImageName.Length ); + ok( info.ImageName.MaximumLength == sizeof(name), "got %#x.\n", info.ImageName.MaximumLength ); + + info.ImageName.Length = 0; + memset( name, 0xcc, sizeof(name) ); + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( !status, "got %#lx.\n", status ); + ok( info.ImageName.Length == length, "got %#x.\n", info.ImageName.Length ); + ok( len == sizeof(info), "got %#lx.\n", len ); + ok( info.ImageName.MaximumLength == info.ImageName.Length + 2, "got %#x.\n", info.ImageName.MaximumLength ); + ok( !name[info.ImageName.Length / 2], "got %#x.\n", name[info.ImageName.Length / 2] ); + + ok( info.ImageName.Length == image_name->Length, "got %#x, %#x.\n", info.ImageName.Length, image_name->Length ); + ok( !wcscmp( name, image_name->Buffer ), "got %s, %s.\n", debugstr_w(name), debugstr_w(image_name->Buffer) ); + + bret = EnumProcesses( pids, sizeof(pids), &len ); + ok( bret, "got error %lu.\n", GetLastError() ); + for (i = 0; i < len / sizeof(*pids); ++i) + { + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pids[i] ); + if (pids[i] && !process && GetLastError() != ERROR_ACCESS_DENIED) + { + /* process is gone already. */ + continue; + } + info.ProcessId = pids[i]; + info.ImageName.Length = 0; + info.ImageName.MaximumLength = sizeof(name); + info.ImageName.Buffer = name; + status = pNtQuerySystemInformation( SystemProcessIdInformation, &info, sizeof(info), &len ); + ok( info.ImageName.Buffer == name || (!info.ImageName.MaximumLength && !info.ImageName.Length), + "got %p, %p, pid %lu, lengh %u / %u.\n", info.ImageName.Buffer, name, pids[i], + info.ImageName.Length, info.ImageName.MaximumLength ); + if (pids[i]) + ok( !status, "got %#lx, pid %lu.\n", status, pids[i] ); + else + ok( status == STATUS_INVALID_CID, "got %#lx, pid %lu.\n", status, pids[i] ); + if (process) CloseHandle( process ); + } +} + START_TEST(info) { char **argv; @@ -3970,4 +4098,5 @@ START_TEST(info) test_process_instrumentation_callback(); test_system_debug_control(); test_process_token(argc, argv); + test_process_id(); } diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 15c4a49e611..6e240e38cad 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -3289,6 +3289,45 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class, break; }
+ case SystemProcessIdInformation: /* 88 */ + { + SYSTEM_PROCESS_ID_INFORMATION *id = info; + UNICODE_STRING *str = &id->ImageName; + ULONG name_len = 0; + void *buffer; + + len = sizeof(*id); + if (ret_size) *ret_size = len; + + if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH; + else if (id->ImageName.Length) ret = STATUS_INVALID_PARAMETER; + else if (!id->ProcessId) ret = STATUS_INVALID_CID; + + if (ret) return ret; + + buffer = malloc( str->MaximumLength ); + SERVER_START_REQ( get_process_image_name ) + { + req->pid = id->ProcessId; + wine_server_set_reply( req, buffer, str->MaximumLength ); + ret = wine_server_call( req ); + name_len = reply->len; + } + SERVER_END_REQ; + + if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH; + if (!ret && name_len + sizeof(WCHAR) > str->MaximumLength) ret = STATUS_INFO_LENGTH_MISMATCH; + if (!ret || ret == STATUS_INFO_LENGTH_MISMATCH) str->MaximumLength = name_len + sizeof(WCHAR); + if (!ret) + { + str->Length = name_len; + memcpy( str->Buffer, buffer, str->Length ); + str->Buffer[str->Length / sizeof(WCHAR)] = 0; + } + free( buffer ); + return ret; + } + case SystemDynamicTimeZoneInformation: /* 102 */ { RTL_DYNAMIC_TIME_ZONE_INFORMATION tz; diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 9535fba3a84..87e219045f4 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -524,6 +524,12 @@ typedef struct ULONG Flags; } SYSTEM_CACHE_INFORMATION32;
+typedef struct +{ + ULONG ProcessId; + UNICODE_STRING32 ImageName; +} SYSTEM_PROCESS_ID_INFORMATION32; + typedef struct { ULONG OwnerPid; diff --git a/dlls/wow64/system.c b/dlls/wow64/system.c index b2c8eec8769..6e78c462984 100644 --- a/dlls/wow64/system.c +++ b/dlls/wow64/system.c @@ -406,6 +406,24 @@ NTSTATUS WINAPI wow64_NtQuerySystemInformation( UINT *args ) } return status;
+ case SystemProcessIdInformation: /* SYSTEM_PROCESS_ID_INFORMATION */ + { + SYSTEM_PROCESS_ID_INFORMATION32 *info32 = ptr; + SYSTEM_PROCESS_ID_INFORMATION info; + + if (retlen) *retlen = sizeof(*info32); + if (len < sizeof(*info32)) return STATUS_INFO_LENGTH_MISMATCH; + + info.ProcessId = info32->ProcessId; + unicode_str_32to64( &info.ImageName, &info32->ImageName ); + if (!(status = NtQuerySystemInformation( class, &info, sizeof(info), NULL ))) + { + info32->ImageName.MaximumLength = info.ImageName.MaximumLength; + info32->ImageName.Length = info.ImageName.Length; + } + return status; + } + case SystemHandleInformation: /* SYSTEM_HANDLE_INFORMATION */ if (len >= sizeof(SYSTEM_HANDLE_INFORMATION32)) { diff --git a/include/winternl.h b/include/winternl.h index 5b897b0276c..22cdceeaedb 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3023,6 +3023,12 @@ typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION UCHAR TableBuffer[1]; } SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION;
+typedef struct _SYSTEM_PROCESS_ID_INFORMATION +{ + ULONG_PTR ProcessId; + UNICODE_STRING ImageName; +} SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION; + typedef struct _TIME_FIELDS { CSHORT Year; CSHORT Month; diff --git a/server/process.c b/server/process.c index b7c7df38e44..f6d1641cb94 100644 --- a/server/process.c +++ b/server/process.c @@ -1512,7 +1512,10 @@ DECL_HANDLER(get_process_debug_info) /* fetch the name of the process image */ DECL_HANDLER(get_process_image_name) { - struct process *process = get_process_from_handle( req->handle, PROCESS_QUERY_LIMITED_INFORMATION ); + struct process *process; + + if (req->pid) process = get_process_from_id( req->pid ); + else process = get_process_from_handle( req->handle, PROCESS_QUERY_LIMITED_INFORMATION );
if (!process) return; if (process->image) diff --git a/server/protocol.def b/server/protocol.def index 69b8db3ebef..f6d644d6182 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1034,6 +1034,7 @@ typedef struct /* Fetch the name of the process image */ @REQ(get_process_image_name) obj_handle_t handle; /* process handle */ + process_id_t pid; /* process id */ int win32; /* return a win32 filename? */ @REPLY data_size_t len; /* len in bytes required to store filename */
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=145297
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:3875: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 00000000006D00D0, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
v2: - allocate a buffer instead of checking output buffer, letting it just get access violation in case of invalid output. That will leak the allocated buffer in case of invalid output but simplifies the code and is probably more "idiomatic" for such syscall implementation; - define ProcessId as ULONG_PTR.