Package: python-psutil Version: 2.1.1-1+b1 Severity: important Tags: patch
When using psutil to query system statistics, several function leak a file handle by returning without closing the file handle. When this is used on a regular basis, the system will fail with too many open file handles: eg. def per_cpu_times(): """Return a list of namedtuple representing the CPU times for every CPU available on the system. """ cpus = [] f = open('/proc/stat', 'rb') try: # get rid of the first line which refers to system wide CPU stats f.readline() CPU = b('cpu') for line in f: if line.startswith(CPU): values = line.split() fields = values[1:len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] entry = scputimes(*fields) cpus.append(entry) return cpus finally: f.close() -- System Information: Debian Release: 8.0 APT prefers unstable APT policy: (500, 'unstable'), (500, 'stable'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 3.17-1-amd64 (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages python-psutil depends on: ii libc6 2.19-13 ii python 2.7.8-2 pn python:any <none> python-psutil recommends no packages. python-psutil suggests no packages. -- no debconf information This message is subject to the following terms and conditions: MAIL DISCLAIMER<http://www.barco.com/en/maildisclaimer>
Description: pslinux leaks several filehandles by returning prematurely This patch closes the filehandles before returning. An alternative way of handling this more cleanly, but a bit larger rewrite, would be to use use a with statement. This would be more clean. . python-psutil (2.1.1-1+barco2) unstable; urgency=low . * patch for misc filehandle leaks in pslinux Author: Marc Leeman <marc.lee...@barco.com> --- python-psutil-2.1.1.orig/psutil/_pslinux.py +++ python-psutil-2.1.1/psutil/_pslinux.py @@ -248,6 +248,7 @@ def per_cpu_times(): fields = [float(x) / CLOCK_TICKS for x in fields] entry = scputimes(*fields) cpus.append(entry) + f.close() return cpus finally: f.close() @@ -339,6 +340,7 @@ def boot_time(): if line.startswith(BTIME): ret = float(line.strip().split()[1]) BOOT_TIME = ret + f.close() return ret raise RuntimeError("line 'btime' not found") finally: @@ -768,7 +770,9 @@ class Process(object): f = open(fname, "rt") try: # return the args as a list - return [x for x in f.read().split('\x00') if x] + r = [x for x in f.read().split('\x00') if x] + f.close() + return r finally: f.close() @@ -862,6 +866,7 @@ class Process(object): f = open("/proc/%s/statm" % self.pid, 'rb') try: vms, rss = f.readline().split()[:2] + f.close() return _common.pmem(int(rss) * PAGESIZE, int(vms) * PAGESIZE) finally: @@ -990,6 +995,7 @@ class Process(object): elif line.startswith(NON_VOLUNTARY): unvol = int(line.split()[1]) if vol is not None and unvol is not None: + f.close() return _common.pctxsw(vol, unvol) raise NotImplementedError( "'voluntary_ctxt_switches' and 'nonvoluntary_ctxt_switches'" @@ -1005,6 +1011,7 @@ class Process(object): THREADS = b("Threads:") for line in f: if line.startswith(THREADS): + f.close() return int(line.split()[1]) raise NotImplementedError("line not found") finally: @@ -1140,7 +1147,9 @@ class Process(object): letter = letter.decode() # XXX is '?' legit? (we're not supposed to return # it anyway) - return PROC_STATUSES.get(letter, '?') + r = PROC_STATUSES.get(letter, '?') + f.close() + return r finally: f.close() @@ -1193,6 +1202,7 @@ class Process(object): for line in f: if line.startswith(PPID): # PPid: nnnn + f.close() return int(line.split()[1]) raise NotImplementedError("line not found") finally: @@ -1206,7 +1216,9 @@ class Process(object): for line in f: if line.startswith(UID): _, real, effective, saved, fs = line.split() - return _common.puids(int(real), int(effective), int(saved)) + r = _common.puids(int(real), int(effective), int(saved)) + f.close() + return r raise NotImplementedError("line not found") finally: f.close() @@ -1219,7 +1231,9 @@ class Process(object): for line in f: if line.startswith(GID): _, real, effective, saved, fs = line.split() - return _common.pgids(int(real), int(effective), int(saved)) + r = _common.pgids(int(real), int(effective), int(saved)) + f.close() + return r raise NotImplementedError("line not found") finally: f.close()