summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Sauthoff <mail@georg.so>2018-03-17 10:31:08 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2018-03-17 10:31:08 +0100
commit6276764eb98eccaef87053dba843694c9232a98c (patch)
treefc7e08353a893be59cad04ca82c58c61f77d7bb8
parentc088fb59a2feb92104caa7752344fccca341b42c (diff)
downloadpsutil-6276764eb98eccaef87053dba843694c9232a98c.tar.gz
Solaris 10 Fixes (#1248)
* Fix nice() for realtime processes under Solaris 10 fixes #1194 * Use psinfo as fallback [gu]id source on Solaris 10 fixes #1193 * Fix double free * Match ssize_t return type of read functions * Fix undefined behavior with respect to strict aliasing rules and fix some warnings For example, under strict aliasing rules of the C standard, casting a char pointer to a struct pointer and accessing the character array through that struct pointer yields undefined behavior. * Update HISTORY with Solaris notes
-rw-r--r--HISTORY.rst7
-rw-r--r--psutil/_pssunos.py50
-rw-r--r--psutil/_psutil_common.c4
-rw-r--r--psutil/_psutil_common.h9
-rw-r--r--psutil/_psutil_sunos.c174
5 files changed, 127 insertions, 117 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index 49e9ed4c..fbf5ac00 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -22,6 +22,13 @@ XXXX-XX-XX
- 1240_: [Windows] cpu_times() float loses accuracy in a long running system.
(patch by stswandering)
- 1245_: [Linux] sensors_temperatures() may fail with IOError "no such file".
+- 1193_: [SunOS] Return uid/gid from /proc/pid/psinfo if there aren't
+ enough permissions for /proc/pid/cred
+- 1194_: [SunOS] Return nice value from psinfo as getpriority() doesn't
+ support real-time processes
+- 1194_: [SunOS] Fix double free in psutil_proc_cpu_num()
+- 1194_: [SunOS] Fix undefined behavior related to strict-aliasing rules
+ and warnings
5.4.3
=====
diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py
index 5471d5aa..35b4b092 100644
--- a/psutil/_pssunos.py
+++ b/psutil/_pssunos.py
@@ -79,7 +79,11 @@ proc_info_map = dict(
nice=4,
num_threads=5,
status=6,
- ttynr=7)
+ ttynr=7,
+ uid=8,
+ euid=9,
+ gid=10,
+ egid=11)
# =====================================================================
@@ -394,7 +398,10 @@ class Process(object):
@memoize_when_activated
def _proc_cred(self):
- return cext.proc_cred(self.pid, self._procfs_path)
+ @wrap_exceptions
+ def proc_cred(self):
+ return cext.proc_cred(self.pid, self._procfs_path)
+ return proc_cred(self)
@wrap_exceptions
def name(self):
@@ -432,27 +439,10 @@ class Process(object):
@wrap_exceptions
def nice_get(self):
- # Note #1: for some reason getpriority(3) return ESRCH (no such
- # process) for certain low-pid processes, no matter what (even
- # as root).
- # The process actually exists though, as it has a name,
- # creation time, etc.
- # The best thing we can do here appears to be raising AD.
- # Note: tested on Solaris 11; on Open Solaris 5 everything is
- # fine.
- #
- # Note #2: we also can get niceness from /proc/pid/psinfo
- # but it's wrong, see:
- # https://github.com/giampaolo/psutil/issues/1082
- try:
- return cext_posix.getpriority(self.pid)
- except EnvironmentError as err:
- # 48 is 'operation not supported' but errno does not expose
- # it. It occurs for low system pids.
- if err.errno in (errno.ENOENT, errno.ESRCH, 48):
- if pid_exists(self.pid):
- raise AccessDenied(self.pid, self._name)
- raise
+ # Note #1: getpriority(3) doesn't work for realtime processes.
+ # Psinfo is what ps uses, see:
+ # https://github.com/giampaolo/psutil/issues/1194
+ return self._proc_basic_info()[proc_info_map['nice']]
@wrap_exceptions
def nice_set(self, value):
@@ -471,12 +461,22 @@ class Process(object):
@wrap_exceptions
def uids(self):
- real, effective, saved, _, _, _ = self._proc_cred()
+ try:
+ real, effective, saved, _, _, _ = self._proc_cred()
+ except AccessDenied:
+ real = self._proc_basic_info()[proc_info_map['uid']]
+ effective = self._proc_basic_info()[proc_info_map['euid']]
+ saved = None
return _common.puids(real, effective, saved)
@wrap_exceptions
def gids(self):
- _, _, _, real, effective, saved = self._proc_cred()
+ try:
+ _, _, _, real, effective, saved = self._proc_cred()
+ except AccessDenied:
+ real = self._proc_basic_info()[proc_info_map['gid']]
+ effective = self._proc_basic_info()[proc_info_map['egid']]
+ saved = None
return _common.puids(real, effective, saved)
@wrap_exceptions
diff --git a/psutil/_psutil_common.c b/psutil/_psutil_common.c
index 908dbf14..e08f011c 100644
--- a/psutil/_psutil_common.c
+++ b/psutil/_psutil_common.c
@@ -40,7 +40,7 @@ PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size) {
* If msg != "" the exception message will change in accordance.
*/
PyObject *
-NoSuchProcess(char *msg) {
+NoSuchProcess(const char *msg) {
PyObject *exc;
exc = PyObject_CallFunction(
PyExc_OSError, "(is)", ESRCH, strlen(msg) ? msg : strerror(ESRCH));
@@ -55,7 +55,7 @@ NoSuchProcess(char *msg) {
* If msg != "" the exception message will change in accordance.
*/
PyObject *
-AccessDenied(char *msg) {
+AccessDenied(const char *msg) {
PyObject *exc;
exc = PyObject_CallFunction(
PyExc_OSError, "(is)", EACCES, strlen(msg) ? msg : strerror(EACCES));
diff --git a/psutil/_psutil_common.h b/psutil/_psutil_common.h
index 3db3f5ed..e107166a 100644
--- a/psutil/_psutil_common.h
+++ b/psutil/_psutil_common.h
@@ -4,6 +4,9 @@
* found in the LICENSE file.
*/
+#ifndef PSUTIL_PSUTIL_COMMON_H
+#define PSUTIL_PSUTIL_COMMON_H
+
#include <Python.h>
extern int PSUTIL_TESTING;
@@ -17,9 +20,11 @@ PyObject* PyUnicode_DecodeFSDefault(char *s);
PyObject* PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size);
#endif
-PyObject* AccessDenied(char *msg);
-PyObject* NoSuchProcess(char *msg);
+PyObject* AccessDenied(const char *msg);
+PyObject* NoSuchProcess(const char *msg);
PyObject* psutil_set_testing(PyObject *self, PyObject *args);
void psutil_debug(const char* format, ...);
void psutil_setup(void);
+
+#endif // PSUTIL_PSUTIL_COMMON_H
diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c
index 4d38a342..99069f56 100644
--- a/psutil/_psutil_sunos.c
+++ b/psutil/_psutil_sunos.c
@@ -46,6 +46,7 @@
#include <inet/tcp.h>
#include <arpa/inet.h>
#include <net/if.h>
+#include <math.h> // fabs()
#include "_psutil_common.h"
#include "_psutil_posix.h"
@@ -58,10 +59,10 @@
/*
* Read a file content and fills a C structure with it.
*/
-int
+static int
psutil_file_to_struct(char *path, void *fstruct, size_t size) {
int fd;
- size_t nbytes;
+ ssize_t nbytes;
fd = open(path, O_RDONLY);
if (fd == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
@@ -73,7 +74,7 @@ psutil_file_to_struct(char *path, void *fstruct, size_t size) {
PyErr_SetFromErrno(PyExc_OSError);
return 0;
}
- if (nbytes != size) {
+ if (nbytes != (ssize_t) size) {
close(fd);
PyErr_SetString(
PyExc_RuntimeError, "read() file structure size mismatch");
@@ -102,17 +103,19 @@ psutil_proc_basic_info(PyObject *self, PyObject *args) {
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
return NULL;
return Py_BuildValue(
- "ikkdiiik",
+ "ikkdiiikiiii",
info.pr_ppid, // parent pid
info.pr_rssize, // rss
info.pr_size, // vms
PSUTIL_TV2DOUBLE(info.pr_start), // create time
- // XXX - niceness is wrong (20 instead of 0), see:
- // https://github.com/giampaolo/psutil/issues/1082
info.pr_lwp.pr_nice, // nice
info.pr_nlwp, // no. of threads
info.pr_lwp.pr_state, // status code
- info.pr_ttydev // tty nr
+ info.pr_ttydev, // tty nr
+ (int)info.pr_uid, // real user id
+ (int)info.pr_euid, // effective user id
+ (int)info.pr_gid, // real group id
+ (int)info.pr_egid // effective group id
);
}
@@ -348,13 +351,11 @@ psutil_proc_cpu_num(PyObject *self, PyObject *args) {
int pid;
char path[1000];
struct prheader header;
- struct lwpsinfo *lwp;
- char *lpsinfo = NULL;
- char *ptr = NULL;
+ struct lwpsinfo *lwp = NULL;
int nent;
int size;
int proc_num;
- size_t nbytes;
+ ssize_t nbytes;
const char *procfs_path;
if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
@@ -382,14 +383,14 @@ psutil_proc_cpu_num(PyObject *self, PyObject *args) {
// malloc
nent = header.pr_nent;
size = header.pr_entsize * nent;
- ptr = lpsinfo = malloc(size);
- if (lpsinfo == NULL) {
+ lwp = malloc(size);
+ if (lwp == NULL) {
PyErr_NoMemory();
goto error;
}
// read the rest
- nbytes = pread(fd, lpsinfo, size, sizeof(header));
+ nbytes = pread(fd, lwp, size, sizeof(header));
if (nbytes == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
@@ -401,20 +402,15 @@ psutil_proc_cpu_num(PyObject *self, PyObject *args) {
}
// done
- lwp = (lwpsinfo_t *)ptr;
proc_num = lwp->pr_onpro;
close(fd);
- free(ptr);
- free(lpsinfo);
+ free(lwp);
return Py_BuildValue("i", proc_num);
error:
if (fd != -1)
close(fd);
- if (ptr != NULL)
- free(ptr);
- if (lpsinfo != NULL)
- free(lpsinfo);
+ free(lwp);
return NULL;
}
@@ -853,7 +849,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
int fd = -1;
char path[1000];
char perms[10];
- char *name;
+ const char *name;
struct stat st;
pstatus_t status;
@@ -1115,11 +1111,11 @@ static PyObject *
psutil_net_connections(PyObject *self, PyObject *args) {
long pid;
int sd = 0;
- mib2_tcpConnEntry_t *tp = NULL;
- mib2_udpEntry_t *ude;
+ mib2_tcpConnEntry_t tp;
+ mib2_udpEntry_t ude;
#if defined(AF_INET6)
- mib2_tcp6ConnEntry_t *tp6;
- mib2_udp6Entry_t *ude6;
+ mib2_tcp6ConnEntry_t tp6;
+ mib2_udp6Entry_t ude6;
#endif
char buf[512];
int i, flags, getcode, num_ent, state;
@@ -1128,10 +1124,10 @@ psutil_net_connections(PyObject *self, PyObject *args) {
int processed_pid;
int databuf_init = 0;
struct strbuf ctlbuf, databuf;
- struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
- struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
- struct T_error_ack *tea = (struct T_error_ack *)buf;
- struct opthdr *mibhdr;
+ struct T_optmgmt_req tor = {0};
+ struct T_optmgmt_ack toa = {0};
+ struct T_error_ack tea = {0};
+ struct opthdr mibhdr = {0};
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
@@ -1164,22 +1160,23 @@ psutil_net_connections(PyObject *self, PyObject *args) {
// which copied and pasted it from netstat source code, mibget()
// function. Also see:
// http://stackoverflow.com/questions/8723598/
- tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
- tor->OPT_offset = sizeof (struct T_optmgmt_req);
- tor->OPT_length = sizeof (struct opthdr);
- tor->MGMT_flags = T_CURRENT;
- mibhdr = (struct opthdr *)&tor[1];
- mibhdr->level = MIB2_IP;
- mibhdr->name = 0;
+ tor.PRIM_type = T_SVR4_OPTMGMT_REQ;
+ tor.OPT_offset = sizeof (struct T_optmgmt_req);
+ tor.OPT_length = sizeof (struct opthdr);
+ tor.MGMT_flags = T_CURRENT;
+ mibhdr.level = MIB2_IP;
+ mibhdr.name = 0;
#ifdef NEW_MIB_COMPLIANT
- mibhdr->len = 1;
+ mibhdr.len = 1;
#else
- mibhdr->len = 0;
+ mibhdr.len = 0;
#endif
+ memcpy(buf, &tor, sizeof tor);
+ memcpy(buf + sizeof tor, &mibhdr, sizeof mibhdr);
ctlbuf.buf = buf;
- ctlbuf.len = tor->OPT_offset + tor->OPT_length;
+ ctlbuf.len = tor.OPT_offset + tor.OPT_length;
flags = 0; // request to be sent in non-priority
if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
@@ -1187,37 +1184,38 @@ psutil_net_connections(PyObject *self, PyObject *args) {
goto error;
}
- mibhdr = (struct opthdr *)&toa[1];
ctlbuf.maxlen = sizeof (buf);
for (;;) {
flags = 0;
getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
+ memcpy(&toa, buf, sizeof toa);
+ memcpy(&tea, buf, sizeof tea);
if (getcode != MOREDATA ||
- ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
- toa->PRIM_type != T_OPTMGMT_ACK ||
- toa->MGMT_flags != T_SUCCESS)
+ ctlbuf.len < (int)sizeof (struct T_optmgmt_ack) ||
+ toa.PRIM_type != T_OPTMGMT_ACK ||
+ toa.MGMT_flags != T_SUCCESS)
{
break;
}
- if (ctlbuf.len >= sizeof (struct T_error_ack) &&
- tea->PRIM_type == T_ERROR_ACK)
+ if (ctlbuf.len >= (int)sizeof (struct T_error_ack) &&
+ tea.PRIM_type == T_ERROR_ACK)
{
PyErr_SetString(PyExc_RuntimeError, "ERROR_ACK");
goto error;
}
if (getcode == 0 &&
- ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
- toa->PRIM_type == T_OPTMGMT_ACK &&
- toa->MGMT_flags == T_SUCCESS)
+ ctlbuf.len >= (int)sizeof (struct T_optmgmt_ack) &&
+ toa.PRIM_type == T_OPTMGMT_ACK &&
+ toa.MGMT_flags == T_SUCCESS)
{
PyErr_SetString(PyExc_RuntimeError, "ERROR_T_OPTMGMT_ACK");
goto error;
}
- databuf.maxlen = mibhdr->len;
+ databuf.maxlen = mibhdr.len;
databuf.len = 0;
- databuf.buf = (char *)malloc((int)mibhdr->len);
+ databuf.buf = (char *)malloc((int)mibhdr.len);
if (!databuf.buf) {
PyErr_NoMemory();
goto error;
@@ -1232,22 +1230,22 @@ psutil_net_connections(PyObject *self, PyObject *args) {
}
// TCPv4
- if (mibhdr->level == MIB2_TCP && mibhdr->name == MIB2_TCP_13) {
- tp = (mib2_tcpConnEntry_t *)databuf.buf;
- num_ent = mibhdr->len / sizeof(mib2_tcpConnEntry_t);
- for (i = 0; i < num_ent; i++, tp++) {
+ if (mibhdr.level == MIB2_TCP && mibhdr.name == MIB2_TCP_13) {
+ num_ent = mibhdr.len / sizeof(mib2_tcpConnEntry_t);
+ for (i = 0; i < num_ent; i++) {
+ memcpy(&tp, databuf.buf + i * sizeof tp, sizeof tp);
#ifdef NEW_MIB_COMPLIANT
- processed_pid = tp->tcpConnCreationProcess;
+ processed_pid = tp.tcpConnCreationProcess;
#else
processed_pid = 0;
#endif
if (pid != -1 && processed_pid != pid)
continue;
// construct local/remote addresses
- inet_ntop(AF_INET, &tp->tcpConnLocalAddress, lip, sizeof(lip));
- inet_ntop(AF_INET, &tp->tcpConnRemAddress, rip, sizeof(rip));
- lport = tp->tcpConnLocalPort;
- rport = tp->tcpConnRemPort;
+ inet_ntop(AF_INET, &tp.tcpConnLocalAddress, lip, sizeof(lip));
+ inet_ntop(AF_INET, &tp.tcpConnRemAddress, rip, sizeof(rip));
+ lport = tp.tcpConnLocalPort;
+ rport = tp.tcpConnRemPort;
// contruct python tuple/list
py_laddr = Py_BuildValue("(si)", lip, lport);
@@ -1260,7 +1258,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
}
if (!py_raddr)
goto error;
- state = tp->tcpConnEntryInfo.ce_state;
+ state = tp.tcpConnEntryInfo.ce_state;
// add item
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM,
@@ -1275,24 +1273,24 @@ psutil_net_connections(PyObject *self, PyObject *args) {
}
#if defined(AF_INET6)
// TCPv6
- else if (mibhdr->level == MIB2_TCP6 && mibhdr->name == MIB2_TCP6_CONN)
+ else if (mibhdr.level == MIB2_TCP6 && mibhdr.name == MIB2_TCP6_CONN)
{
- tp6 = (mib2_tcp6ConnEntry_t *)databuf.buf;
- num_ent = mibhdr->len / sizeof(mib2_tcp6ConnEntry_t);
+ num_ent = mibhdr.len / sizeof(mib2_tcp6ConnEntry_t);
- for (i = 0; i < num_ent; i++, tp6++) {
+ for (i = 0; i < num_ent; i++) {
+ memcpy(&tp6, databuf.buf + i * sizeof tp6, sizeof tp6);
#ifdef NEW_MIB_COMPLIANT
- processed_pid = tp6->tcp6ConnCreationProcess;
+ processed_pid = tp6.tcp6ConnCreationProcess;
#else
processed_pid = 0;
#endif
if (pid != -1 && processed_pid != pid)
continue;
// construct local/remote addresses
- inet_ntop(AF_INET6, &tp6->tcp6ConnLocalAddress, lip, sizeof(lip));
- inet_ntop(AF_INET6, &tp6->tcp6ConnRemAddress, rip, sizeof(rip));
- lport = tp6->tcp6ConnLocalPort;
- rport = tp6->tcp6ConnRemPort;
+ inet_ntop(AF_INET6, &tp6.tcp6ConnLocalAddress, lip, sizeof(lip));
+ inet_ntop(AF_INET6, &tp6.tcp6ConnRemAddress, rip, sizeof(rip));
+ lport = tp6.tcp6ConnLocalPort;
+ rport = tp6.tcp6ConnRemPort;
// contruct python tuple/list
py_laddr = Py_BuildValue("(si)", lip, lport);
@@ -1304,7 +1302,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_raddr = Py_BuildValue("()");
if (!py_raddr)
goto error;
- state = tp6->tcp6ConnEntryInfo.ce_state;
+ state = tp6.tcp6ConnEntryInfo.ce_state;
// add item
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM,
@@ -1318,13 +1316,13 @@ psutil_net_connections(PyObject *self, PyObject *args) {
}
#endif
// UDPv4
- else if (mibhdr->level == MIB2_UDP || mibhdr->level == MIB2_UDP_ENTRY) {
- ude = (mib2_udpEntry_t *)databuf.buf;
- num_ent = mibhdr->len / sizeof(mib2_udpEntry_t);
- assert(num_ent * sizeof(mib2_udpEntry_t) == mibhdr->len);
- for (i = 0; i < num_ent; i++, ude++) {
+ else if (mibhdr.level == MIB2_UDP || mibhdr.level == MIB2_UDP_ENTRY) {
+ num_ent = mibhdr.len / sizeof(mib2_udpEntry_t);
+ assert(num_ent * sizeof(mib2_udpEntry_t) == mibhdr.len);
+ for (i = 0; i < num_ent; i++) {
+ memcpy(&ude, databuf.buf + i * sizeof ude, sizeof ude);
#ifdef NEW_MIB_COMPLIANT
- processed_pid = ude->udpCreationProcess;
+ processed_pid = ude.udpCreationProcess;
#else
processed_pid = 0;
#endif
@@ -1337,8 +1335,8 @@ psutil_net_connections(PyObject *self, PyObject *args) {
// to do other than skipping.
if (processed_pid > 131072)
continue;
- inet_ntop(AF_INET, &ude->udpLocalAddress, lip, sizeof(lip));
- lport = ude->udpLocalPort;
+ inet_ntop(AF_INET, &ude.udpLocalAddress, lip, sizeof(lip));
+ lport = ude.udpLocalPort;
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
@@ -1357,21 +1355,21 @@ psutil_net_connections(PyObject *self, PyObject *args) {
}
#if defined(AF_INET6)
// UDPv6
- else if (mibhdr->level == MIB2_UDP6 ||
- mibhdr->level == MIB2_UDP6_ENTRY)
+ else if (mibhdr.level == MIB2_UDP6 ||
+ mibhdr.level == MIB2_UDP6_ENTRY)
{
- ude6 = (mib2_udp6Entry_t *)databuf.buf;
- num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t);
- for (i = 0; i < num_ent; i++, ude6++) {
+ num_ent = mibhdr.len / sizeof(mib2_udp6Entry_t);
+ for (i = 0; i < num_ent; i++) {
+ memcpy(&ude6, databuf.buf + i * sizeof ude6, sizeof ude6);
#ifdef NEW_MIB_COMPLIANT
- processed_pid = ude6->udp6CreationProcess;
+ processed_pid = ude6.udp6CreationProcess;
#else
processed_pid = 0;
#endif
if (pid != -1 && processed_pid != pid)
continue;
- inet_ntop(AF_INET6, &ude6->udp6LocalAddress, lip, sizeof(lip));
- lport = ude6->udp6LocalPort;
+ inet_ntop(AF_INET6, &ude6.udp6LocalAddress, lip, sizeof(lip));
+ lport = ude6.udp6LocalPort;
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
@@ -1421,7 +1419,7 @@ psutil_boot_time(PyObject *self, PyObject *args) {
}
}
endutxent();
- if (boot_time == 0.0) {
+ if (fabs(boot_time) < 0.000001) {
/* could not find BOOT_TIME in getutxent loop */
PyErr_SetString(PyExc_RuntimeError, "can't determine boot time");
return NULL;