From 0c0840a465e91ba1ceac699709b8a09cb4960ace Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 1 Oct 2023 22:50:54 +0200 Subject: [PATCH] Win: fix OpenProcess not recognizing when proc is gone. This is due to ExitCodeProcess needing PROCESS_QUERY_INFORMATION access rights. --- make.bat | 1 + psutil/__init__.py | 3 +++ psutil/arch/windows/proc.c | 16 +++++++++++----- psutil/tests/test_process.py | 5 ----- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/make.bat b/make.bat index 2c79d4291..2ac53d9ec 100644 --- a/make.bat +++ b/make.bat @@ -31,5 +31,6 @@ if "%TSCRIPT%" == "" ( rem Needed to locate the .pypirc file and upload exes on PyPI. set HOME=%USERPROFILE% +set PSUTIL_DEBUG=1 %PYTHON% scripts\internal\winmake.py %1 %2 %3 %4 %5 %6 diff --git a/psutil/__init__.py b/psutil/__init__.py index 6e7be6391..5a5a20606 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1227,6 +1227,9 @@ def send_signal(self, sig): self._send_signal(sig) else: # pragma: no cover self._raise_if_pid_reused() + if sig != signal.SIGTERM and not self.is_running(): + msg = "process no longer exists" + raise NoSuchProcess(self.pid, self._name, msg=msg) self._proc.send_signal(sig) def suspend(self): diff --git a/psutil/arch/windows/proc.c b/psutil/arch/windows/proc.c index d9b69744f..af3df267a 100644 --- a/psutil/arch/windows/proc.c +++ b/psutil/arch/windows/proc.c @@ -99,14 +99,14 @@ PyObject * psutil_proc_kill(PyObject *self, PyObject *args) { HANDLE hProcess; DWORD pid; + DWORD access = PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION; if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) return NULL; if (pid == 0) return AccessDenied("automatically set for PID 0"); - hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - hProcess = psutil_check_phandle(hProcess, pid, 0); + hProcess = psutil_handle_from_pid(pid, access); if (hProcess == NULL) { return NULL; } @@ -272,6 +272,11 @@ psutil_proc_exe(PyObject *self, PyObject *args) { if (pid == 0) return AccessDenied("automatically set for PID 0"); + // ...because NtQuerySystemInformation can succeed for terminated + // processes. + if (psutil_pid_is_running(pid) == 0) + return NoSuchProcess("psutil_pid_is_running -> 0"); + buffer = MALLOC_ZERO(bufferSize); if (! buffer) { PyErr_NoMemory(); @@ -535,12 +540,13 @@ psutil_proc_suspend_or_resume(PyObject *self, PyObject *args) { DWORD pid; NTSTATUS status; HANDLE hProcess; + DWORD access = PROCESS_SUSPEND_RESUME | PROCESS_QUERY_LIMITED_INFORMATION; PyObject* suspend; - if (! PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &suspend)) - return NULL; + if (! PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &suspend)) + return NULL; - hProcess = psutil_handle_from_pid(pid, PROCESS_SUSPEND_RESUME); + hProcess = psutil_handle_from_pid(pid, access); if (hProcess == NULL) return NULL; diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py index 48d3db983..ae0192708 100755 --- a/psutil/tests/test_process.py +++ b/psutil/tests/test_process.py @@ -1301,11 +1301,6 @@ def assert_raises_nsp(fun, fun_name): for fun, name in ns.iter(ns.all): assert_raises_nsp(fun, name) - # NtQuerySystemInformation succeeds even if process is gone. - if WINDOWS and not GITHUB_ACTIONS: - normcase = os.path.normcase - self.assertEqual(normcase(p.exe()), normcase(PYTHON_EXE)) - @unittest.skipIf(not POSIX, 'POSIX only') def test_zombie_process(self): parent, zombie = self.spawn_zombie()