From aadac57bb7ebbddb12e31b4715f499d03fc92896 Mon Sep 17 00:00:00 2001 From: Ben Peddell Date: Wed, 1 Jan 2025 18:12:14 +1000 Subject: [PATCH] Handle STATUS_INVALID_PARAMETER in psutil_proc_exe Wine versions before 9.8 and Proton versions before 9.0-1 did not implement the `SystemProcessIdInformation` system information class in `NtQuerySystemInformation`, returning `STATUS_INVALID_PARAMETER`. Ubuntu 24.04.1 LTS currently ships with Wine 9.0, and CrossOver 24.0.5 has not backported the implementation of the `SystemProcessIdInformation` system information class to its bundled Wine 9.0 Handle this error case and fall back to `QueryFullProcessImageNameW` to get the process name. --- psutil/arch/windows/proc.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/psutil/arch/windows/proc.c b/psutil/arch/windows/proc.c index 41fa9dda6..5e1e830b6 100644 --- a/psutil/arch/windows/proc.c +++ b/psutil/arch/windows/proc.c @@ -261,6 +261,8 @@ psutil_proc_exe(PyObject *self, PyObject *args) { ULONG bufferSize = 0x104 * 2; // WIN_MAX_PATH * sizeof(wchar_t) SYSTEM_PROCESS_ID_INFORMATION processIdInfo; PyObject *py_exe; + HANDLE hProcess; + DWORD size; if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) return NULL; @@ -333,6 +335,39 @@ psutil_proc_exe(PyObject *self, PyObject *args) { sizeof(SYSTEM_PROCESS_ID_INFORMATION), NULL); } + else if (status == STATUS_INVALID_PARAMETER) { + FREE(buffer); + hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION); + + if (NULL == hProcess) + return NULL; + + buffer = MALLOC_ZERO(bufferSize); + if (! buffer) { + PyErr_NoMemory(); + return NULL; + } + + size = bufferSize / 2; + + if (QueryFullProcessImageNameW(hProcess, 0, buffer, &size) == 0) { + FREE(buffer); + // https://github.com/giampaolo/psutil/issues/1662 + if (GetLastError() == 0) + AccessDenied("QueryFullProcessImageNameW (forced EPERM)"); + else + psutil_PyErr_SetFromOSErrnoWithSyscall("QueryFullProcessImageNameW"); + CloseHandle(hProcess); + return NULL; + } + + CloseHandle(hProcess); + + processIdInfo.ImageName.Buffer = buffer; + processIdInfo.ImageName.Length = (USHORT)(size * 2); + + status = 0; // STATUS_SUCCESS + } if (! NT_SUCCESS(status)) { FREE(buffer);