8000 Issue #1731717: Fixed the problem where subprocess.wait() could cause an · python/cpython@e85db2b · GitHub
[go: up one dir, main page]

Skip to content

Commit e85db2b

Browse files
committed
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.
1 parent 32ef70c commit e85db2b

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

Lib/subprocess.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,11 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
12951295
os.close(errpipe_read)
12961296

12971297
if data:
1298-
_eintr_retry_call(os.waitpid, self.pid, 0)
1298+
try:
1299+
_eintr_retry_call(os.waitpid, self.pid, 0)
1300+
except OSError as e:
1301+
if e.errno != errno.ECHILD:
1302+
raise
12991303
try:
13001304
exception_name, hex_errno, err_msg = data.split(b':', 2)
13011305
except ValueError:
@@ -1358,7 +1362,15 @@ def wait(self):
13581362
"""Wait for child process to terminate. Returns returncode
13591363
attribute."""
13601364
if self.returncode is None:
1361-
pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
1365+
try:
1366+
pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
1367+
except OSError as e:
1368+
if e.errno != errno.ECHILD:
1369+
raise
1370+
# This happens if SIGCLD is set to be ignored or waiting
1371+
# for child processes has otherwise been disabled for our
1372+
# process. This child is dead, we can't get the status.
1373+
sts = 0
13621374
self._handle_exitstatus(sts)
13631375
return self.returncode
13641376

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import signal, subprocess, sys
2+
# On Linux this causes os.waitpid to fail with OSError as the OS has already
3+
# reaped our child process. The wait() passing the OSError on to the caller
4+
# and causing us to exit with an error is what we are testing against.
5+
signal.signal(signal.SIGCLD, signal.SIG_IGN)
6+
subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait()

Lib/test/test_subprocess.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,16 @@ def test_pass_fds(self):
10731073
close_fds=False, pass_fds=(fd, )))
10741074
self.assertIn('overriding close_fds', str(context.warning))
10751075

1076+
def test_wait_when_sigchild_ignored(self):
1077+
# NOTE: sigchild_ignore.py may not be an effective test on all OSes.
1078+
sigchild_ignore = support.findfile("sigchild_ignore.py",
1079+
subdir="subprocessdata")
1080+
p = subprocess.Popen([sys.executable, sigchild_ignore],
1081+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1082+
stdout, stderr = p.communicate()
1083+
self.assertEqual(0, p.returncode, "sigchild_ignore.py exited"
1084+
" non-zero with this error:\n%s" % stderr)
1085+
10761086

10771087
@unittest.skipUnless(mswindows, "Windows specific tests")
10781088
class Win32ProcessTestCase(BaseTestCase):

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ Library
3333
added in 3.2beta1) to allow specifying a specific list of file descriptors
3434
to keep open in the child process.
3535

36+
- Issue #1731717: Fixed the problem where subprocess.wait() could cause an
37+
OSError exception when The OS had been told to ignore SIGCLD in our process
38+
or otherwise not wait for exiting child processes.
39+
3640

3741
What's New in Python 3.2 Beta 1?
3842
================================

0 commit comments

Comments
 (0)
0