summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2016-09-11 21:26:10 +0200
committerGiampaolo Rodola <g.rodola@gmail.com>2016-09-11 21:26:10 +0200
commitd5958a6f5f3ee29dc92d86e1ff47766b5d403ad6 (patch)
treeccb41e07504314d4d1be4fe0f0553060870a8a1f
parentb625a80babb6ea437127f5b180ae92c3c2162fb6 (diff)
parent601f959a398c80596dbcde1edefe387588b6fbc0 (diff)
downloadpsutil-d5958a6f5f3ee29dc92d86e1ff47766b5d403ad6.tar.gz
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r--CREDITS6
-rw-r--r--HISTORY.rst1
-rw-r--r--psutil/_psutil_windows.c153
3 files changed, 130 insertions, 30 deletions
diff --git a/CREDITS b/CREDITS
index d1639260..206f1a55 100644
--- a/CREDITS
+++ b/CREDITS
@@ -402,3 +402,9 @@ I: 870
N: Yago Jesus
W: https://github.com/YJesus
I: 798
+
+N: Andre Caron
+C: Montreal, QC, Canada
+E: andre.l.caron@gmail.com
+W: https://github.com/AndreLouisCaron
+I: 880
diff --git a/HISTORY.rst b/HISTORY.rst
index 8cf81d4a..55232265 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -30,6 +30,7 @@ Bug tracker at https://github.com/giampaolo/psutil/issues
- #869: [Windows] Process.wait() may raise TimeoutExpired with wrong timeout
unit (ms instead of sec).
- #870: [Windows] Handle leak inside psutil_get_process_data.
+- #880: [Windows] Handle race condition inside psutil_net_connections.
4.3.0 - 2016-06-18
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index 8b80f27d..31f9d86a 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -1469,6 +1469,88 @@ psutil_proc_username(PyObject *self, PyObject *args) {
}
+typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG,
+ TCP_TABLE_CLASS, ULONG);
+
+
+// https://msdn.microsoft.com/library/aa365928.aspx
+static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call,
+ ULONG address_family,
+ PVOID * data, DWORD * size)
+{
+ // Due to other processes being active on the machine, it's possible
+ // that the size of the table increases between the moment where we
+ // query the size and the moment where we query the data. Therefore, it's
+ // important to call this in a loop to retry if that happens.
+ //
+ // Also, since we may loop a theoretically unbounded number of times here,
+ // release the GIL while we're doing this.
+ DWORD error = ERROR_INSUFFICIENT_BUFFER;
+ *size = 0;
+ *data = NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ error = call(NULL, size, FALSE, address_family,
+ TCP_TABLE_OWNER_PID_ALL, 0);
+ while (error == ERROR_INSUFFICIENT_BUFFER)
+ {
+ *data = malloc(*size);
+ if (*data == NULL) {
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ continue;
+ }
+ error = call(*data, size, FALSE, address_family,
+ TCP_TABLE_OWNER_PID_ALL, 0);
+ if (error != NO_ERROR) {
+ free(*data);
+ *data = NULL;
+ }
+ }
+ Py_END_ALLOW_THREADS;
+ return error;
+}
+
+
+typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG,
+ UDP_TABLE_CLASS, ULONG);
+
+
+// https://msdn.microsoft.com/library/aa365930.aspx
+static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call,
+ ULONG address_family,
+ PVOID * data, DWORD * size)
+{
+ // Due to other processes being active on the machine, it's possible
+ // that the size of the table increases between the moment where we
+ // query the size and the moment where we query the data. Therefore, it's
+ // important to call this in a loop to retry if that happens.
+ //
+ // Also, since we may loop a theoretically unbounded number of times here,
+ // release the GIL while we're doing this.
+ DWORD error = ERROR_INSUFFICIENT_BUFFER;
+ *size = 0;
+ *data = NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ error = call(NULL, size, FALSE, address_family,
+ UDP_TABLE_OWNER_PID, 0);
+ while (error == ERROR_INSUFFICIENT_BUFFER)
+ {
+ *data = malloc(*size);
+ if (*data == NULL) {
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ continue;
+ }
+ error = call(*data, size, FALSE, address_family,
+ UDP_TABLE_OWNER_PID, 0);
+ if (error != NO_ERROR) {
+ free(*data);
+ *data = NULL;
+ }
+ }
+ Py_END_ALLOW_THREADS;
+ return error;
+}
+
+
/*
* Return a list of network connections opened by a process
*/
@@ -1480,14 +1562,11 @@ psutil_net_connections(PyObject *self, PyObject *args) {
_RtlIpv4AddressToStringA rtlIpv4AddressToStringA;
typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
_RtlIpv6AddressToStringA rtlIpv6AddressToStringA;
- typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG,
- TCP_TABLE_CLASS, ULONG);
_GetExtendedTcpTable getExtendedTcpTable;
- typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG,
- UDP_TABLE_CLASS, ULONG);
_GetExtendedUdpTable getExtendedUdpTable;
PVOID table = NULL;
DWORD tableSize;
+ DWORD error;
PMIB_TCPTABLE_OWNER_PID tcp4Table;
PMIB_UDPTABLE_OWNER_PID udp4Table;
PMIB_TCP6TABLE_OWNER_PID tcp6Table;
@@ -1570,17 +1649,15 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET,
- TCP_TABLE_OWNER_PID_ALL, 0);
- table = malloc(tableSize);
- if (table == NULL) {
+ error = __GetExtendedTcpTable(getExtendedTcpTable,
+ AF_INET, &table, &tableSize);
+ if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
goto error;
}
- if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET,
- TCP_TABLE_OWNER_PID_ALL, 0) == 0)
+ if (error == NO_ERROR)
{
tcp4Table = table;
@@ -1650,8 +1727,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
Py_DECREF(py_conn_tuple);
}
}
+ else {
+ PyErr_SetFromWindowsErr(error);
+ goto error;
+ }
free(table);
+ table = NULL;
+ tableSize = 0;
}
// TCP IPv6
@@ -1663,17 +1746,15 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6,
- TCP_TABLE_OWNER_PID_ALL, 0);
- table = malloc(tableSize);
- if (table == NULL) {
+ error = __GetExtendedTcpTable(getExtendedTcpTable,
+ AF_INET6, &table, &tableSize);
+ if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
goto error;
}
- if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET6,
- TCP_TABLE_OWNER_PID_ALL, 0) == 0)
+ if (error == NO_ERROR)
{
tcp6Table = table;
@@ -1743,8 +1824,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
Py_DECREF(py_conn_tuple);
}
}
+ else {
+ PyErr_SetFromWindowsErr(error);
+ goto error;
+ }
free(table);
+ table = NULL;
+ tableSize = 0;
}
// UDP IPv4
@@ -1757,17 +1844,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET,
- UDP_TABLE_OWNER_PID, 0);
-
- table = malloc(tableSize);
- if (table == NULL) {
+ error = __GetExtendedUdpTable(getExtendedUdpTable,
+ AF_INET, &table, &tableSize);
+ if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
goto error;
}
- if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET,
- UDP_TABLE_OWNER_PID, 0) == 0)
+ if (error == NO_ERROR)
{
udp4Table = table;
@@ -1814,8 +1898,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
Py_DECREF(py_conn_tuple);
}
}
+ else {
+ PyErr_SetFromWindowsErr(error);
+ goto error;
+ }
free(table);
+ table = NULL;
+ tableSize = 0;
}
// UDP IPv6
@@ -1828,17 +1918,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- getExtendedUdpTable(NULL, &tableSize, FALSE,
- AF_INET6, UDP_TABLE_OWNER_PID, 0);
-
- table = malloc(tableSize);
- if (table == NULL) {
+ error = __GetExtendedUdpTable(getExtendedUdpTable,
+ AF_INET6, &table, &tableSize);
+ if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
goto error;
}
- if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET6,
- UDP_TABLE_OWNER_PID, 0) == 0)
+ if (error == NO_ERROR)
{
udp6Table = table;
@@ -1884,8 +1971,14 @@ psutil_net_connections(PyObject *self, PyObject *args) {
Py_DECREF(py_conn_tuple);
}
}
+ else {
+ PyErr_SetFromWindowsErr(error);
+ goto error;
+ }
free(table);
+ table = NULL;
+ tableSize = 0;
}
_psutil_conn_decref_objs();