diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2019-02-27 14:32:21 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2019-02-27 14:32:21 +0100 |
commit | b31f3bf778004f1eae6ac552dd8eb8419664ac73 (patch) | |
tree | acddc47b163b688da55a2857e62dfb5253623d2c | |
parent | e827bf46381d3d996d63e064834aa421e502d8b8 (diff) | |
download | psutil-b31f3bf778004f1eae6ac552dd8eb8419664ac73.tar.gz |
#1291 / OSX: mark memory_maps() as deprecated and make it alwats raise AccessDenied
-rw-r--r-- | HISTORY.rst | 5 | ||||
-rw-r--r-- | docs/index.rst | 67 | ||||
-rw-r--r-- | psutil/__init__.py | 1 | ||||
-rw-r--r-- | psutil/_common.py | 2 | ||||
-rw-r--r-- | psutil/_psaix.py | 5 | ||||
-rw-r--r-- | psutil/_psosx.py | 13 | ||||
-rw-r--r-- | psutil/_psutil_osx.c | 160 | ||||
-rw-r--r-- | psutil/tests/__init__.py | 2 | ||||
-rwxr-xr-x | psutil/tests/test_contracts.py | 10 | ||||
-rwxr-xr-x | psutil/tests/test_osx.py | 3 | ||||
-rwxr-xr-x | psutil/tests/test_process.py | 4 |
11 files changed, 56 insertions, 216 deletions
diff --git a/HISTORY.rst b/HISTORY.rst index 26eff418..5313a091 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -40,6 +40,11 @@ XXXX-XX-XX - 1439_: [NetBSD] Process.connections() may return incomplete results if using oneshot() +**API changes** + +- 1291_: [OSX] Process.memory_maps() is deprecated and will always raise + AccessDenied. It will be removed in psutil 6.0.0. + 5.5.1 ===== diff --git a/docs/index.rst b/docs/index.rst index 78a88f97..6d464c85 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1675,48 +1675,47 @@ Process class See `pmap.py <https://github.com/giampaolo/psutil/blob/master/scripts/pmap.py>`__ for an example application. - +---------------+--------------+---------+-----------+--------------+ - | Linux | macOS | Windows | Solaris | FreeBSD | - +===============+==============+=========+===========+==============+ - | rss | rss | rss | rss | rss | - +---------------+--------------+---------+-----------+--------------+ - | size | private | | anonymous | private | - +---------------+--------------+---------+-----------+--------------+ - | pss | swapped | | locked | ref_count | - +---------------+--------------+---------+-----------+--------------+ - | shared_clean | dirtied | | | shadow_count | - +---------------+--------------+---------+-----------+--------------+ - | shared_dirty | ref_count | | | | - +---------------+--------------+---------+-----------+--------------+ - | private_clean | shadow_depth | | | | - +---------------+--------------+---------+-----------+--------------+ - | private_dirty | | | | | - +---------------+--------------+---------+-----------+--------------+ - | referenced | | | | | - +---------------+--------------+---------+-----------+--------------+ - | anonymous | | | | | - +---------------+--------------+---------+-----------+--------------+ - | swap | | | | | - +---------------+--------------+---------+-----------+--------------+ + +---------------+---------+--------------+-----------+ + | Linux | Windows | FreeBSD | Solaris | + +===============+=========+==============+===========+ + | rss | rss | rss | rss | + +---------------+---------+--------------+-----------+ + | size | | private | anonymous | + +---------------+---------+--------------+-----------+ + | pss | | ref_count | locked | + +---------------+---------+--------------+-----------+ + | shared_clean | | shadow_count | | + +---------------+---------+--------------+-----------+ + | shared_dirty | | | | + +---------------+---------+--------------+-----------+ + | private_clean | | | | + +---------------+---------+--------------+-----------+ + | private_dirty | | | | + +---------------+---------+--------------+-----------+ + | referenced | | | | + +---------------+---------+--------------+-----------+ + | anonymous | | | | + +---------------+---------+--------------+-----------+ + | swap | | | | + +---------------+---------+--------------+-----------+ >>> import psutil >>> p = psutil.Process() >>> p.memory_maps() [pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0), pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0), - pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, swap=0), - pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0), - pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0), - ...] - >>> p.memory_maps(grouped=False) - [pmmap_ext(addr='00400000-006ea000', perms='r-xp', path='/usr/bin/python2.7', rss=2293760, size=3055616, pss=1157120, shared_clean=2273280, shared_dirty=0, private_clean=20480, private_dirty=0, referenced=2293760, anonymous=0, swap=0), - pmmap_ext(addr='008e9000-008eb000', perms='r--p', path='/usr/bin/python2.7', rss=8192, size=8192, pss=6144, shared_clean=4096, shared_dirty=0, private_clean=0, private_dirty=4096, referenced=8192, anonymous=4096, swap=0), - pmmap_ext(addr='008eb000-00962000', perms='rw-p', path='/usr/bin/python2.7', rss=417792, size=487424, pss=317440, shared_clean=200704, shared_dirty=0, private_clean=16384, private_dirty=200704, referenced=417792, anonymous=200704, swap=0), - pmmap_ext(addr='00962000-00985000', perms='rw-p', path='[anon]', rss=139264, size=143360, pss=139264, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=139264, referenced=139264, anonymous=139264, swap=0), - pmmap_ext(addr='02829000-02ccf000', perms='rw-p', path='[heap]', rss=4743168, size=4874240, pss=4743168, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=4743168, referenced=4718592, anonymous=4743168, swap=0), ...] - Availability: All platforms except OpenBSD, NetBSD and AIX. + Availability: Linux, Windows, FreeBSD, SunOS + + .. warning:: + on macOS, starting from version 5.6.0, this function is deprecated and + will always raise :class:`psutil.AccessDenied`. It is scheduled for + removal in 6.0.0 + (see `issue 1020 <https://github.com/giampaolo/psutil/issues/1291#issuecomment-467828376>`_). + + .. versionchanged:: + 5.6.0 deprecated on macOS, always raise AccessDenied .. method:: children(recursive=False) diff --git a/psutil/__init__.py b/psutil/__init__.py index 447e507b..d8ec701c 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1218,7 +1218,6 @@ class Process(object): return (value / float(total_phymem)) * 100 if hasattr(_psplatform.Process, "memory_maps"): - # Available everywhere except OpenBSD and NetBSD. def memory_maps(self, grouped=True): """Return process' mapped memory regions as a list of namedtuples whose fields are variable depending on the platform. diff --git a/psutil/_common.py b/psutil/_common.py index b809a79f..6d430388 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -475,7 +475,7 @@ def deprecated_method(replacement): @functools.wraps(fun) def inner(self, *args, **kwargs): - warnings.warn(msg, category=FutureWarning, stacklevel=2) + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return getattr(self, replacement)(*args, **kwargs) return inner return outer diff --git a/psutil/_psaix.py b/psutil/_psaix.py index 58ecf17f..96ed9476 100644 --- a/psutil/_psaix.py +++ b/psutil/_psaix.py @@ -97,11 +97,6 @@ pfullmem = pmem scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait']) # psutil.virtual_memory() svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) -# psutil.Process.memory_maps(grouped=True) -pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked']) -# psutil.Process.memory_maps(grouped=False) -pmmap_ext = namedtuple( - 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) # ===================================================================== diff --git a/psutil/_psosx.py b/psutil/_psosx.py index 72b343f5..78f710aa 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -8,6 +8,7 @@ import contextlib import errno import functools import os +import warnings from socket import AF_INET from collections import namedtuple @@ -107,13 +108,6 @@ svmem = namedtuple( pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins']) # psutil.Process.memory_full_info() pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', )) -# psutil.Process.memory_maps(grouped=True) -pmmap_grouped = namedtuple( - 'pmmap_grouped', - 'path rss private swapped dirtied ref_count shadow_depth') -# psutil.Process.memory_maps(grouped=False) -pmmap_ext = namedtuple( - 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) # ===================================================================== @@ -582,6 +576,7 @@ class Process(object): retlist.append(ntuple) return retlist - @wrap_exceptions def memory_maps(self): - return cext.proc_memory_maps(self.pid) + msg = "memory_maps() on OSX is deprecated and will be removed in 6.0.0" + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) + raise AccessDenied(self.pid, msg=msg) diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c index 02b2172d..eaf4e514 100644 --- a/psutil/_psutil_osx.c +++ b/psutil/_psutil_osx.c @@ -342,164 +342,6 @@ psutil_proc_environ(PyObject *self, PyObject *args) { /* - * Return a list of tuples for every process memory maps. - * 'procstat' cmdline utility has been used as an example. - * This will fail for all processes except os.getpid(), - * even as root. - */ -static PyObject * -psutil_proc_memory_maps(PyObject *self, PyObject *args) { - char buf[PATH_MAX]; - char addr_str[34]; - char perms[8]; - int pagesize = getpagesize(); - int iteration = 0; - long pid; - kern_return_t kr; - mach_port_t task = MACH_PORT_NULL; - uint32_t depth = 1; - vm_address_t address = 0; - vm_size_t size = 0; - struct vm_region_submap_info_64 info; - mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; - PyObject *py_tuple = NULL; - PyObject *py_path = NULL; - PyObject *py_list = PyList_New(0); - - if (py_list == NULL) - return NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - if (psutil_task_for_pid(pid, &task) != 0) - goto error; - - while (1) { - iteration += 1; - py_tuple = NULL; - kr = vm_region_recurse_64(task, &address, &size, &depth, - (vm_region_info_64_t)&info, &count); - if (kr != KERN_SUCCESS) { - if ((kr == KERN_INVALID_ADDRESS) && (iteration > 1)) { - break; // no more regions to read - } - PyErr_Format( - PyExc_RuntimeError, - "vm_region_recurse_64() failed: %s", - mach_error_string(kr)); - goto error; - } - - if (info.is_submap) { - depth++; - } - else { - // Free/Reset the char[]s to avoid weird paths - memset(buf, 0, sizeof(buf)); - memset(addr_str, 0, sizeof(addr_str)); - memset(perms, 0, sizeof(perms)); - - sprintf(addr_str, - "%016lx-%016lx", - (long unsigned int)address, - (long unsigned int)address + size); - sprintf(perms, "%c%c%c/%c%c%c", - (info.protection & VM_PROT_READ) ? 'r' : '-', - (info.protection & VM_PROT_WRITE) ? 'w' : '-', - (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', - (info.max_protection & VM_PROT_READ) ? 'r' : '-', - (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', - (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-'); - - // proc_regionfilename() is undocumented but from its source - // code we can determine that it sets errno on error and - // return length of path. - errno = 0; - proc_regionfilename((pid_t)pid, address, buf, sizeof(buf)); - if (errno != 0) { - psutil_debug("proc_regionfilename() failed errno=%i", errno); - psutil_raise_for_pid(pid, "proc_regionfilename()"); - goto error; - } - - if (info.share_mode == SM_COW && info.ref_count == 1) { - // Treat single reference SM_COW as SM_PRIVATE - info.share_mode = SM_PRIVATE; - } - - if (strlen(buf) == 0) { - switch (info.share_mode) { -// #ifdef SM_LARGE_PAGE - // case SM_LARGE_PAGE: - // Treat SM_LARGE_PAGE the same as SM_PRIVATE - // since they are not shareable and are wired. -// #endif - case SM_COW: - strcpy(buf, "[cow]"); - break; - case SM_PRIVATE: - strcpy(buf, "[prv]"); - break; - case SM_EMPTY: - strcpy(buf, "[nul]"); - break; - case SM_SHARED: - case SM_TRUESHARED: - strcpy(buf, "[shm]"); - break; - case SM_PRIVATE_ALIASED: - strcpy(buf, "[ali]"); - break; - case SM_SHARED_ALIASED: - strcpy(buf, "[s/a]"); - break; - default: - strcpy(buf, "[???]"); - } - } - - py_path = PyUnicode_DecodeFSDefault(buf); - if (! py_path) - goto error; - py_tuple = Py_BuildValue( - "ssOIIIIIH", - addr_str, // "start-end"address - perms, // "rwx" permissions - py_path, // path - info.pages_resident * pagesize, // rss - info.pages_shared_now_private * pagesize, // private - info.pages_swapped_out * pagesize, // swapped - info.pages_dirtied * pagesize, // dirtied - info.ref_count, // ref count - info.shadow_depth // shadow depth - ); - if (!py_tuple) - goto error; - if (PyList_Append(py_list, py_tuple)) - goto error; - Py_DECREF(py_tuple); - Py_DECREF(py_path); - - // increment address for the next map/file - address += size; - } - } - - if (task != MACH_PORT_NULL) - mach_port_deallocate(mach_task_self(), task); - - return py_list; - -error: - if (task != MACH_PORT_NULL) - mach_port_deallocate(mach_task_self(), task); - Py_XDECREF(py_tuple); - Py_XDECREF(py_path); - Py_DECREF(py_list); - return NULL; -} - - -/* * Return the number of logical CPUs in the system. * XXX this could be shared with BSD. */ @@ -1931,8 +1773,6 @@ PsutilMethods[] = { "Return the number of fds opened by process."}, {"proc_connections", psutil_proc_connections, METH_VARARGS, "Get process TCP and UDP connections as a list of tuples"}, - {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, - "Return a list of tuples for every process's memory map"}, // --- system-related functions diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py index 545f5f25..86af2cfb 100644 --- a/psutil/tests/__init__.py +++ b/psutil/tests/__init__.py @@ -167,7 +167,7 @@ HAS_ENVIRON = hasattr(psutil.Process, "environ") HAS_PROC_IO_COUNTERS = hasattr(psutil.Process, "io_counters") HAS_IONICE = hasattr(psutil.Process, "ionice") HAS_MEMORY_FULL_INFO = 'uss' in psutil.Process().memory_full_info()._fields -HAS_MEMORY_MAPS = hasattr(psutil.Process, "memory_maps") +HAS_MEMORY_MAPS = not MACOS and hasattr(psutil.Process, "memory_maps") HAS_PROC_CPU_NUM = hasattr(psutil.Process, "cpu_num") HAS_RLIMIT = hasattr(psutil.Process, "rlimit") HAS_THREADS = hasattr(psutil.Process, "threads") diff --git a/psutil/tests/test_contracts.py b/psutil/tests/test_contracts.py index 5ea4ba1c..97a1a0f0 100755 --- a/psutil/tests/test_contracts.py +++ b/psutil/tests/test_contracts.py @@ -181,10 +181,18 @@ class TestDeprecations(unittest.TestCase): with warnings.catch_warnings(record=True) as ws: psutil.Process().memory_info_ex() w = ws[0] - self.assertIsInstance(w.category(), FutureWarning) + self.assertIsInstance(w.category(), DeprecationWarning) self.assertIn("memory_info_ex() is deprecated", str(w.message)) self.assertIn("use memory_info() instead", str(w.message)) + @unittest.skipIf(not MACOS, "deprecated on macOS") + def test_memory_maps_osx(self): + with warnings.catch_warnings(record=True) as ws: + with self.assertRaises(psutil.AccessDenied): + psutil.Process().memory_maps() + w = ws[0] + self.assertIsInstance(w.category(), DeprecationWarning) + # =================================================================== # --- System API types diff --git a/psutil/tests/test_osx.py b/psutil/tests/test_osx.py index cf5c5ea8..40257190 100755 --- a/psutil/tests/test_osx.py +++ b/psutil/tests/test_osx.py @@ -158,9 +158,6 @@ class TestZombieProcessAPIs(unittest.TestCase): self.assertRaises((psutil.ZombieProcess, psutil.AccessDenied), self.p.threads) - def test_memory_maps(self): - self.assertRaises(psutil.ZombieProcess, self.p.memory_maps) - @unittest.skipIf(not MACOS, "MACOS only") class TestSystemAPIs(unittest.TestCase): diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py index 16c0ba4a..31f42eba 100755 --- a/psutil/tests/test_process.py +++ b/psutil/tests/test_process.py @@ -1265,7 +1265,7 @@ class TestProcess(unittest.TestCase): p.send_signal(signal.CTRL_BREAK_EVENT) excluded_names = ['pid', 'is_running', 'wait', 'create_time', - 'oneshot'] + 'oneshot', 'memory_info_ex'] if LINUX and not HAS_RLIMIT: excluded_names.append('rlimit') for name in dir(p): @@ -1291,6 +1291,8 @@ class TestProcess(unittest.TestCase): ret = meth([0]) elif name == 'send_signal': ret = meth(signal.SIGTERM) + elif MACOS and name == 'memory_maps': + continue # XXX else: ret = meth() except psutil.ZombieProcess: |