Skip to content

Commit

Permalink
fix #1179 / linux / cmdline: handle processes erroneously overwriting…
Browse files Browse the repository at this point in the history
… /proc/pid/cmdline by using spaces instead of null bytes as args separator
  • Loading branch information
giampaolo committed Nov 28, 2017
1 parent bb27cbf commit 7c6b6c2
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
3 changes: 3 additions & 0 deletions HISTORY.rst
Expand Up @@ -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
Expand Down
12 changes: 10 additions & 2 deletions psutil/_pslinux.py
Expand Up @@ -1471,9 +1471,17 @@ def cmdline(self):
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):
Expand Down
14 changes: 14 additions & 0 deletions psutil/tests/test_linux.py
Expand Up @@ -1585,6 +1585,20 @@ def test_cmdline_mocked(self):
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)'):
Expand Down

0 comments on commit 7c6b6c2

Please sign in to comment.