diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-09-11 21:26:10 +0200 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-09-11 21:26:10 +0200 |
commit | d5958a6f5f3ee29dc92d86e1ff47766b5d403ad6 (patch) | |
tree | ccb41e07504314d4d1be4fe0f0553060870a8a1f | |
parent | b625a80babb6ea437127f5b180ae92c3c2162fb6 (diff) | |
parent | 601f959a398c80596dbcde1edefe387588b6fbc0 (diff) | |
download | psutil-d5958a6f5f3ee29dc92d86e1ff47766b5d403ad6.tar.gz |
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r-- | CREDITS | 6 | ||||
-rw-r--r-- | HISTORY.rst | 1 | ||||
-rw-r--r-- | psutil/_psutil_windows.c | 153 |
3 files changed, 130 insertions, 30 deletions
@@ -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(); |