diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2017-11-28 11:10:42 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2017-11-28 11:10:42 +0100 |
commit | 7c6b6c2a6d89a1a270d6357be3b77fd8e0e2cbe7 (patch) | |
tree | 87661f89858ff721d11c62e80390cdc61ecb9c3b | |
parent | bb27cbf65c5abf91ad0b6c2725c0527b8132f75d (diff) | |
download | psutil-7c6b6c2a6d89a1a270d6357be3b77fd8e0e2cbe7.tar.gz |
fix #1179 / linux / cmdline: handle processes erroneously overwriting /proc/pid/cmdline by using spaces instead of null bytes as args separator
-rw-r--r-- | HISTORY.rst | 3 | ||||
-rw-r--r-- | psutil/_pslinux.py | 12 | ||||
-rwxr-xr-x | psutil/tests/test_linux.py | 14 |
3 files changed, 27 insertions, 2 deletions
diff --git a/HISTORY.rst b/HISTORY.rst index 430fb5e4..bfaa2568 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -17,6 +17,9 @@ - 1169_: [Linux] users() "hostname" returns username instead. (patch by janderbrain) - 1172_: [Windows] `make test` does not work. +- 1179_: [Linux] Process.cmdline() correctly splits cmdline args for + misbehaving processes who overwrite /proc/pid/cmdline by using spaces + instead of null bytes as args separator. - 1181_: [OSX] Process.memory_maps() may raise ENOENT. 5.4.1 diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 3fe62c5c..a5a3fd89 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1471,9 +1471,17 @@ class Process(object): if not data: # may happen in case of zombie process return [] - if data.endswith('\x00'): + # 'man proc' states that args are separated by null bytes '\0' + # and last char is supposed to be a null byte. Nevertheless + # some processes may change their cmdline after being started + # (via setproctitle() or similar), they are usually not + # compliant with this rule and use spaces instead. Google + # Chrome process is an example. See: + # https://github.com/giampaolo/psutil/issues/1179 + sep = '\x00' if data.endswith('\x00') else ' ' + if data.endswith(sep): data = data[:-1] - return [x for x in data.split('\x00')] + return [x for x in data.split(sep)] @wrap_exceptions def environ(self): diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index 71d428c3..6ba17b25 100755 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -1585,6 +1585,20 @@ class TestProcess(unittest.TestCase): self.assertEqual(p.cmdline(), ['foo', 'bar', '']) assert m.called + def test_cmdline_spaces_mocked(self): + # see: https://github.com/giampaolo/psutil/issues/1179 + p = psutil.Process() + fake_file = io.StringIO(u('foo bar ')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + self.assertEqual(p.cmdline(), ['foo', 'bar']) + assert m.called + fake_file = io.StringIO(u('foo bar ')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + self.assertEqual(p.cmdline(), ['foo', 'bar', '']) + assert m.called + def test_readlink_path_deleted_mocked(self): with mock.patch('psutil._pslinux.os.readlink', return_value='/home/foo (deleted)'): |