]> granicus.if.org Git - python/commitdiff
Issue #1731717: Fixed the problem where subprocess.wait() could cause an
authorGregory P. Smith <greg@mad-scientist.com>
Tue, 14 Dec 2010 14:38:00 +0000 (14:38 +0000)
committerGregory P. Smith <greg@mad-scientist.com>
Tue, 14 Dec 2010 14:38:00 +0000 (14:38 +0000)
OSError exception when The OS had been told to ignore SIGCLD in our process
or otherwise not wait for exiting child processes.

Lib/subprocess.py
Lib/test/subprocessdata/sigchild_ignore.py [new file with mode: 0644]
Lib/test/test_subprocess.py
Misc/NEWS

index ac46ce85c07610addcef06449e97c21593889975..452611c5a9a108cb990ca92bbd22a57d92c64eb0 100644 (file)
@@ -1295,7 +1295,11 @@ class Popen(object):
                 os.close(errpipe_read)
 
             if data:
-                _eintr_retry_call(os.waitpid, self.pid, 0)
+                try:
+                    _eintr_retry_call(os.waitpid, self.pid, 0)
+                except OSError as e:
+                    if e.errno != errno.ECHILD:
+                        raise
                 try:
                     exception_name, hex_errno, err_msg = data.split(b':', 2)
                 except ValueError:
@@ -1358,7 +1362,15 @@ class Popen(object):
             """Wait for child process to terminate.  Returns returncode
             attribute."""
             if self.returncode is None:
-                pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
+                try:
+                    pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
+                except OSError as e:
+                    if e.errno != errno.ECHILD:
+                        raise
+                    # This happens if SIGCLD is set to be ignored or waiting
+                    # for child processes has otherwise been disabled for our
+                    # process.  This child is dead, we can't get the status.
+                    sts = 0
                 self._handle_exitstatus(sts)
             return self.returncode
 
diff --git a/Lib/test/subprocessdata/sigchild_ignore.py b/Lib/test/subprocessdata/sigchild_ignore.py
new file mode 100644 (file)
index 0000000..1d03303
--- /dev/null
@@ -0,0 +1,6 @@
+import signal, subprocess, sys
+# On Linux this causes os.waitpid to fail with OSError as the OS has already
+# reaped our child process.  The wait() passing the OSError on to the caller
+# and causing us to exit with an error is what we are testing against.
+signal.signal(signal.SIGCLD, signal.SIG_IGN)
+subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait()
index 0804a1322542750497c60c91182c84f3acc3ccd9..1e97bac0189d0a4750ab5de50829d78ea2532209 100644 (file)
@@ -1073,6 +1073,16 @@ class POSIXProcessTestCase(BaseTestCase):
                         close_fds=False, pass_fds=(fd, )))
             self.assertIn('overriding close_fds', str(context.warning))
 
+    def test_wait_when_sigchild_ignored(self):
+        # NOTE: sigchild_ignore.py may not be an effective test on all OSes.
+        sigchild_ignore = support.findfile("sigchild_ignore.py",
+                                           subdir="subprocessdata")
+        p = subprocess.Popen([sys.executable, sigchild_ignore],
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        self.assertEqual(0, p.returncode, "sigchild_ignore.py exited"
+                         " non-zero with this error:\n%s" % stderr)
+
 
 @unittest.skipUnless(mswindows, "Windows specific tests")
 class Win32ProcessTestCase(BaseTestCase):
index d2a2c42b87971833cfa60906a0fc8fe5855e9ca3..981b53f49a75e9f11bc57ba6f53f482735e66dd2 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -33,6 +33,10 @@ Library
   added in 3.2beta1) to allow specifying a specific list of file descriptors
   to keep open in the child process.
 
+- Issue #1731717: Fixed the problem where subprocess.wait() could cause an
+  OSError exception when The OS had been told to ignore SIGCLD in our process
+  or otherwise not wait for exiting child processes.
+
 
 What's New in Python 3.2 Beta 1?
 ================================