Charles-François Natali <neolo...@free.fr> added the comment:
With comment.
I'll add a similar comment to default.
----------
Added file: http://bugs.python.org/file23032/subprocess_cloexec-1.diff
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue12786>
_______________________________________
diff -r d4d9a3e71897 Lib/subprocess.py
--- a/Lib/subprocess.py Tue Aug 23 19:54:20 2011 +0200
+++ b/Lib/subprocess.py Wed Aug 24 22:36:58 2011 +0200
@@ -1035,7 +1035,7 @@
if stdin is None:
pass
elif stdin == PIPE:
- p2cread, p2cwrite = os.pipe()
+ p2cread, p2cwrite = self._pipe2()
elif isinstance(stdin, int):
p2cread = stdin
else:
@@ -1045,7 +1045,7 @@
if stdout is None:
pass
elif stdout == PIPE:
- c2pread, c2pwrite = os.pipe()
+ c2pread, c2pwrite = self._pipe2()
elif isinstance(stdout, int):
c2pwrite = stdout
else:
@@ -1055,7 +1055,7 @@
if stderr is None:
pass
elif stderr == PIPE:
- errread, errwrite = os.pipe()
+ errread, errwrite = self._pipe2()
elif stderr == STDOUT:
errwrite = c2pwrite
elif isinstance(stderr, int):
@@ -1082,6 +1082,19 @@
fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag)
+ def _pipe2(self, cloexec=True):
+ """Ad-hoc pipe2() implementation."""
+ # Pipes are set CLOEXEC by default because we don't want them to be
+ # inherited by other subprocesses: the CLOEXEC flag is removed from
+ # the child's pipes by _dup2(), between fork() and exec().
+ # This is not atomic: we would need the pipe2() syscall for that.
+ r, w = os.pipe()
+ if cloexec:
+ self._set_cloexec_flag(r)
+ self._set_cloexec_flag(w)
+ return r, w
+
+
def _close_fds(self, but):
if hasattr(os, 'closerange'):
os.closerange(3, but)
@@ -1120,11 +1133,9 @@
# For transferring possible exec failure from child to parent
# The first char specifies the exception type: 0 means
# OSError, 1 means some other error.
- errpipe_read, errpipe_write = os.pipe()
+ errpipe_read, errpipe_write = self._pipe2()
try:
try:
- self._set_cloexec_flag(errpipe_write)
-
gc_was_enabled = gc.isenabled()
# Disable gc to avoid bug where gc -> file_dealloc ->
# write to stderr -> hang.
http://bugs.python.org/issue1336
diff -r d4d9a3e71897 Lib/test/test_subprocess.py
--- a/Lib/test/test_subprocess.py Tue Aug 23 19:54:20 2011 +0200
+++ b/Lib/test/test_subprocess.py Wed Aug 24 22:36:58 2011 +0200
@@ -995,6 +995,37 @@
self.assertRaises(OSError, os.waitpid, pid, 0)
self.assertNotIn(ident, [id(o) for o in subprocess._active])
+ def test_pipe_cloexec(self):
+ # Issue 12786: check that the parent-end FDs of the communication pipes
+ # are set CLOEXEC, and not inherited by another child process.
+ p1 = subprocess.Popen([sys.executable, "-c",
+ 'import os;'
+ 'os.read(0)'
+ ],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ p2 = subprocess.Popen([sys.executable, "-c", """if True:
+ import os, errno, sys
+ for fd in %r:
+ try:
+ os.close(fd)
+ except OSError as e:
+ if e.errno != errno.EBADF:
+ raise
+ else:
+ sys.exit(1)
+ sys.exit(0)
+ """ % [f.fileno() for f in (p1.stdin, p1.stdout,
+ p1.stderr)]
+ ],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, close_fds=False)
+ p1.communicate('foo')
+ _, stderr = p2.communicate()
+
+ self.assertEqual(p2.returncode, 0, "Unexpected error: " + repr(stderr))
+
@unittest.skipUnless(mswindows, "Windows specific tests")
class Win32ProcessTestCase(BaseTestCase):
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com