diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2022-10-19 02:28:14 +0200 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2022-10-19 02:28:14 +0200 |
commit | aa9a4f6f9bfaca1dd1d22034d007bbf5d86b9670 (patch) | |
tree | 106256b2c758aa7253c6b23a67b0938f0795acc2 | |
parent | 1da9f7928e79ecc127768e7a5bc4eb7f785f4513 (diff) | |
download | psutil-linux-zombie-proc.tar.gz |
raise ZombieProcess instead of AccessDenied if process is a zombielinux-zombie-proc
-rw-r--r-- | HISTORY.rst | 11 | ||||
-rw-r--r-- | psutil/__init__.py | 2 | ||||
-rw-r--r-- | psutil/_pslinux.py | 28 | ||||
-rwxr-xr-x | psutil/tests/test_process.py | 6 |
4 files changed, 44 insertions, 3 deletions
diff --git a/HISTORY.rst b/HISTORY.rst index e9833990..b742cd8d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,5 +1,16 @@ *Bug tracker at https://github.com/giampaolo/psutil/issues* +5.9.4 (IN DEVELOPMENT) +====================== + +XXXX-XX-XX + +**Bug fixes** + +- XXXX_, [Linux]: when process is a zombie, certain methods like + `Process.open_files()`_, `Process.environ()`_ and `Process.io_counters + ()`_ erroneously raise ``AccessDenied`` instead of ``ZombieProcess``. + 5.9.3 ===== diff --git a/psutil/__init__.py b/psutil/__init__.py index ca2d9273..56742791 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -211,7 +211,7 @@ if hasattr(_psplatform.Process, "rlimit"): AF_LINK = _psplatform.AF_LINK __author__ = "Giampaolo Rodola'" -__version__ = "5.9.3" +__version__ = "5.9.4" version_info = tuple([int(num) for num in __version__.split('.')]) _timer = getattr(time, 'monotonic', time.time) diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 9dc9643a..c16db892 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1635,6 +1635,20 @@ def ppid_map(): return ret +def is_zombie(pid): + try: + data = bcat("%s/%s/stat" % (get_procfs_path(), pid)) + except EnvironmentError: + return False + else: + # Process name is between parentheses. It can contain spaces and + # other parentheses. This is taken into account by looking for + # the first occurrence of "(" and the last occurrence of ")". + rpar = data.rfind(b')') + fields = data[rpar + 2:].split() + return fields[0] == "Z" + + def wrap_exceptions(fun): """Decorator which translates bare OSError and IOError exceptions into NoSuchProcess and AccessDenied. @@ -1644,9 +1658,19 @@ def wrap_exceptions(fun): try: return fun(self, *args, **kwargs) except PermissionError: - raise AccessDenied(self.pid, self._name) + # Linux is peculiar in that accessing certain pseudo files + # like /proc/pid/fd/*, /proc/pid/environ and /proc/pid/io + # results in EPERM if process is a zombie. In such cases it + # appears more correct to raise ZP instead of AD. + if is_zombie(self.pid): + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise AccessDenied(self.pid, self._name) except ProcessLookupError: - raise NoSuchProcess(self.pid, self._name) + if is_zombie(self.pid): + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise NoSuchProcess(self.pid, self._name) except FileNotFoundError: if not os.path.exists("%s/%s" % (self._procfs_path, self.pid)): raise NoSuchProcess(self.pid, self._name) diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py index 26869e98..bd31ac66 100755 --- a/psutil/tests/test_process.py +++ b/psutil/tests/test_process.py @@ -1324,6 +1324,12 @@ class TestProcess(PsutilTestCase): for fun, name in ns.iter(ns.all): succeed_or_zombie_p_exc(fun) + if LINUX: + # TODO: broken + # self.assertRaises(psutil.ZombieProcess, zproc.exe) + self.assertRaises(psutil.ZombieProcess, zproc.cwd) + self.assertRaises(psutil.ZombieProcess, zproc.memory_full_info) + assert psutil.pid_exists(zproc.pid) self.assertIn(zproc.pid, psutil.pids()) self.assertIn(zproc.pid, [x.pid for x in psutil.process_iter()]) |