]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.7] bpo-35182: fix communicate() crash after child closes its pipes (GH-18117)...
authorAlex Rebert <alex@forallsecure.com>
Thu, 23 Jan 2020 23:32:31 +0000 (18:32 -0500)
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 23 Jan 2020 23:32:31 +0000 (15:32 -0800)
When communicate() is called in a loop, it crashes when the child process
has already closed any piped standard stream, but still continues to be running

Co-authored-by: Andriy Maletsky <andriy.maletsky@gmail.com>.
(cherry picked from commit d3ae95e1e945ed20297e1c38ba43a18b7a868ab6)

Co-authored-by: Alex Rebert <alex@forallsecure.com>
https://bugs.python.org/issue35182

Automerge-Triggered-By: @gpshead
Lib/subprocess.py
Lib/test/test_subprocess.py
Misc/NEWS.d/next/Library/2019-10-31-19-23-25.bpo-35182.hzeNl9.rst [new file with mode: 0644]

index d1b6de57857899112777794574a52659f35a31fc..3f99be551c5152d2278deb2ef6bc94ed4362f5c4 100644 (file)
@@ -1697,9 +1697,9 @@ class Popen(object):
             with _PopenSelector() as selector:
                 if self.stdin and input:
                     selector.register(self.stdin, selectors.EVENT_WRITE)
-                if self.stdout:
+                if self.stdout and not self.stdout.closed:
                     selector.register(self.stdout, selectors.EVENT_READ)
-                if self.stderr:
+                if self.stderr and not self.stderr.closed:
                     selector.register(self.stderr, selectors.EVENT_READ)
 
                 while selector.get_map():
index 9f494dab408ca6393fad130d9af7af43eeb6b87d..d024158e18a59d4fbe2f0b5a4927889b0f7b33d6 100644 (file)
@@ -2848,6 +2848,17 @@ class POSIXProcessTestCase(BaseTestCase):
 
         self.assertEqual(returncode, -3)
 
+    def test_communicate_repeated_call_after_stdout_close(self):
+        proc = subprocess.Popen([sys.executable, '-c',
+                                 'import os, time; os.close(1), time.sleep(2)'],
+                                stdout=subprocess.PIPE)
+        while True:
+            try:
+                proc.communicate(timeout=0.1)
+                return
+            except subprocess.TimeoutExpired:
+                pass
+
 
 @unittest.skipUnless(mswindows, "Windows specific tests")
 class Win32ProcessTestCase(BaseTestCase):
diff --git a/Misc/NEWS.d/next/Library/2019-10-31-19-23-25.bpo-35182.hzeNl9.rst b/Misc/NEWS.d/next/Library/2019-10-31-19-23-25.bpo-35182.hzeNl9.rst
new file mode 100644 (file)
index 0000000..9438cd8
--- /dev/null
@@ -0,0 +1,3 @@
+Fixed :func:`Popen.communicate` subsequent call crash when the child process
+has already closed any piped standard stream, but still continues to be
+running. Patch by Andriy Maletsky.