summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/subprocess.py16
-rw-r--r--Lib/test/subprocessdata/sigchild_ignore.py6
-rw-r--r--Lib/test/test_subprocess.py10
-rw-r--r--Misc/NEWS4
4 files changed, 34 insertions, 2 deletions
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index ac46ce8..452611c 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -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
index 0000000..1d03303
--- /dev/null
+++ b/Lib/test/subprocessdata/sigchild_ignore.py
@@ -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()
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 0804a13..1e97bac 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -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):
diff --git a/Misc/NEWS b/Misc/NEWS
index d2a2c42..981b53f 100644
--- 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?
================================