]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #12494: Close pipes and kill process on error in subprocess functions
authorVictor Stinner <victor.stinner@haypocalc.com>
Thu, 1 Sep 2011 21:45:04 +0000 (23:45 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Thu, 1 Sep 2011 21:45:04 +0000 (23:45 +0200)
On error, call(), check_call(), check_output() and getstatusoutput() functions
of the subprocess module now kill the process, read its status (to avoid
zombis) and close pipes.

Lib/subprocess.py
Misc/NEWS

index db64588697c13ff6c0e1990bb81b368651389230..2c5c888910c32177a8ca24d8862204a9aa4fe876 100644 (file)
@@ -464,13 +464,13 @@ def call(*popenargs, timeout=None, **kwargs):
 
     retcode = call(["ls", "-l"])
     """
-    p = Popen(*popenargs, **kwargs)
-    try:
-        return p.wait(timeout=timeout)
-    except TimeoutExpired:
-        p.kill()
-        p.wait()
-        raise
+    with Popen(*popenargs, **kwargs) as p:
+        try:
+            return p.wait(timeout=timeout)
+        except:
+            p.kill()
+            p.wait()
+            raise
 
 
 def check_call(*popenargs, **kwargs):
@@ -514,16 +514,20 @@ def check_output(*popenargs, timeout=None, **kwargs):
     """
     if 'stdout' in kwargs:
         raise ValueError('stdout argument not allowed, it will be overridden.')
-    process = Popen(*popenargs, stdout=PIPE, **kwargs)
-    try:
-        output, unused_err = process.communicate(timeout=timeout)
-    except TimeoutExpired:
-        process.kill()
-        output, unused_err = process.communicate()
-        raise TimeoutExpired(process.args, timeout, output=output)
-    retcode = process.poll()
-    if retcode:
-        raise CalledProcessError(retcode, process.args, output=output)
+    with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
+        try:
+            output, unused_err = process.communicate(timeout=timeout)
+        except TimeoutExpired:
+            process.kill()
+            output, unused_err = process.communicate()
+            raise TimeoutExpired(process.args, timeout, output=output)
+        except:
+            process.kill()
+            process.wait()
+            raise
+        retcode = process.poll()
+        if retcode:
+            raise CalledProcessError(retcode, process.args, output=output)
     return output
 
 
@@ -618,11 +622,19 @@ def getstatusoutput(cmd):
     >>> subprocess.getstatusoutput('/bin/junk')
     (256, 'sh: /bin/junk: not found')
     """
-    pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
-    text = pipe.read()
-    sts = pipe.close()
-    if sts is None: sts = 0
-    if text[-1:] == '\n': text = text[:-1]
+    with os.popen('{ ' + cmd + '; } 2>&1', 'r') as pipe:
+        try:
+            text = pipe.read()
+            sts = pipe.close()
+        except:
+            process = pipe._proc
+            process.kill()
+            process.wait()
+            raise
+    if sts is None:
+        sts = 0
+    if text[-1:] == '\n':
+        text = text[:-1]
     return sts, text
 
 
index 57a1237104c99053c212b94575f1f545c8046cb0..01b72812bfd43a1e2d8ee43b2e67563fe87a32a6 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -271,6 +271,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #12494: On error, call(), check_call(), check_output() and
+  getstatusoutput() functions of the subprocess module now kill the process,
+  read its status (to avoid zombis) and close pipes.
+
 - Issue #12720: Expose low-level Linux extended file attribute functions in os.
 
 - Issue #10946: The distutils commands bdist_dumb, bdist_wininst and bdist_msi