Should help with Overwatch 2 random crashes after some time of playing.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/info.c | 129 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/system.c | 37 +++++++++++ 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, 201 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 6771bbe4e3f..787210f7f4e 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -22,6 +22,7 @@ #include <winnls.h> #include <ddk/ntddk.h> #include <stdio.h> +#include <psapi.h>
static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtSetSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG); @@ -3832,6 +3833,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 = (void *)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 = (void *)(ULONG_PTR)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 = (void *)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 = NULL; + 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 = NULL; + 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 = (void *)(ULONG_PTR)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 = (void *)(ULONG_PTR)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; @@ -3909,4 +4037,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..0b98f578ae2 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -3289,6 +3289,43 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class, break; }
+ case SystemProcessIdInformation: /* 88 */ + { + SYSTEM_PROCESS_ID_INFORMATION *id = info; + UNICODE_STRING *str = &id->ImageName; + BOOL valid_buffer; + + len = sizeof(*id); + 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) break; + + valid_buffer = virtual_check_buffer_for_write( str->Buffer, str->MaximumLength ); + SERVER_START_REQ( get_process_image_name ) + { + req->pid = HandleToULong( id->ProcessId ); + if (valid_buffer) wine_server_set_reply( req, str->Buffer, str->MaximumLength ); + ret = wine_server_call( req ); + if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH; + if (ret == STATUS_SUCCESS && reply->len + 2 > str->MaximumLength) ret = STATUS_INFO_LENGTH_MISMATCH; + if (ret == STATUS_SUCCESS || ret == STATUS_INFO_LENGTH_MISMATCH) str->MaximumLength = reply->len + 2; + if (!ret && valid_buffer) + { + str->Length = reply->len; + str->Buffer[reply->len / 2] = 0; + } + else if (!valid_buffer && (!ret || ret == STATUS_INFO_LENGTH_MISMATCH)) + { + str->Length = reply->len; + ret = STATUS_ACCESS_VIOLATION; + } + } + SERVER_END_REQ; + break; + } + case SystemDynamicTimeZoneInformation: /* 102 */ { RTL_DYNAMIC_TIME_ZONE_INFORMATION tz; diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 2c4cf4f9e3c..7be9b86ee5c 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..e32db6f8794 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_INFORMATION32 *info32 = ptr; + SYSTEM_PROCESS_ID_INFORMATION info; + + if (retlen) *retlen = sizeof(*info32); + if (len < sizeof(*info32)) return STATUS_INFO_LENGTH_MISMATCH; + + info.ProcessId = ULongToHandle( 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 c39d6427e52..588c5f46c97 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 +{ + void *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 55dda2d7636..4839d0a48de 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1021,6 +1021,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 */
Nikolay Sivov (@nsivov) commented about include/winternl.h:
UCHAR TableBuffer[1];
} SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION;
+typedef struct _SYSTEM_PROCESS_ID_INFORMATION +{
- void *ProcessId;
Maybe ULONG_PTR is better for this one.
On Mon Apr 15 10:03:34 2024 +0000, Nikolay Sivov wrote:
Maybe ULONG_PTR is better for this one.
Well, PVOID is how Geoff Chappell defines it [1]. Elsewhere in somewhat similar occasion we define as HANDLE (see CLIENT_ID in winternl.h) which is essentially 'void *' but HANDLE is IMO most confusing because this is not handle but id. So I am not sure, ULONG_PTR is most straightforward ofc but for some reason is usually defined elsewise.
1. https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/pro...
On Mon Apr 15 16:54:48 2024 +0000, Paul Gofman wrote:
Well, PVOID is how Geoff Chappell defines it [1]. Elsewhere in somewhat similar occasion we define as HANDLE (see CLIENT_ID in winternl.h) which is essentially 'void *' but HANDLE is IMO most confusing because this is not handle but id. So I am not sure, ULONG_PTR is most straightforward ofc but for some reason is usually defined elsewise.
Yes, HANDLE is probably worse.