summaryrefslogtreecommitdiff
path: root/dev-lang/python/files/python-2.7-issue18851.patch
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@gentoo.org>2015-08-08 13:49:04 -0700
committerRobin H. Johnson <robbat2@gentoo.org>2015-08-08 17:38:18 -0700
commit56bd759df1d0c750a065b8c845e93d5dfa6b549d (patch)
tree3f91093cdb475e565ae857f1c5a7fd339e2d781e /dev-lang/python/files/python-2.7-issue18851.patch
downloadgentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.gz
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.bz2
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.zip
proj/gentoo: Initial commit
This commit represents a new era for Gentoo: Storing the gentoo-x86 tree in Git, as converted from CVS. This commit is the start of the NEW history. Any historical data is intended to be grafted onto this point. Creation process: 1. Take final CVS checkout snapshot 2. Remove ALL ChangeLog* files 3. Transform all Manifests to thin 4. Remove empty Manifests 5. Convert all stale $Header$/$Id$ CVS keywords to non-expanded Git $Id$ 5.1. Do not touch files with -kb/-ko keyword flags. Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> X-Thanks: Alec Warner <antarus@gentoo.org> - did the GSoC 2006 migration tests X-Thanks: Robin H. Johnson <robbat2@gentoo.org> - infra guy, herding this project X-Thanks: Nguyen Thai Ngoc Duy <pclouds@gentoo.org> - Former Gentoo developer, wrote Git features for the migration X-Thanks: Brian Harring <ferringb@gentoo.org> - wrote much python to improve cvs2svn X-Thanks: Rich Freeman <rich0@gentoo.org> - validation scripts X-Thanks: Patrick Lauer <patrick@gentoo.org> - Gentoo dev, running new 2014 work in migration X-Thanks: Michał Górny <mgorny@gentoo.org> - scripts, QA, nagging X-Thanks: All of other Gentoo developers - many ideas and lots of paint on the bikeshed
Diffstat (limited to 'dev-lang/python/files/python-2.7-issue18851.patch')
-rw-r--r--dev-lang/python/files/python-2.7-issue18851.patch287
1 files changed, 287 insertions, 0 deletions
diff --git a/dev-lang/python/files/python-2.7-issue18851.patch b/dev-lang/python/files/python-2.7-issue18851.patch
new file mode 100644
index 000000000000..35c69ae22e80
--- /dev/null
+++ b/dev-lang/python/files/python-2.7-issue18851.patch
@@ -0,0 +1,287 @@
+# HG changeset patch
+# User Antoine Pitrou <solipsis@pitrou.net>
+# Date 1377898693 -7200
+# Node ID 43749cb6bdbd0fdab70f76cd171c3c02a3f600dd
+# Parent ba54011aa295004ad87438211fe3bb1568dd69ab
+Issue #18851: Avoid a double close of subprocess pipes when the child process fails starting.
+
+diff --git a/Lib/subprocess.py b/Lib/subprocess.py
+--- a/Lib/subprocess.py
++++ b/Lib/subprocess.py
+@@ -698,12 +698,12 @@ class Popen(object):
+
+ (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+- errread, errwrite) = self._get_handles(stdin, stdout, stderr)
++ errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
+
+ try:
+ self._execute_child(args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+- startupinfo, creationflags, shell,
++ startupinfo, creationflags, shell, to_close,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+@@ -711,18 +711,12 @@ class Popen(object):
+ # Preserve original exception in case os.close raises.
+ exc_type, exc_value, exc_trace = sys.exc_info()
+
+- to_close = []
+- # Only close the pipes we created.
+- if stdin == PIPE:
+- to_close.extend((p2cread, p2cwrite))
+- if stdout == PIPE:
+- to_close.extend((c2pread, c2pwrite))
+- if stderr == PIPE:
+- to_close.extend((errread, errwrite))
+-
+ for fd in to_close:
+ try:
+- os.close(fd)
++ if mswindows:
++ fd.Close()
++ else:
++ os.close(fd)
+ except EnvironmentError:
+ pass
+
+@@ -816,8 +810,9 @@ class Popen(object):
+ """Construct and return tuple with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
++ to_close = set()
+ if stdin is None and stdout is None and stderr is None:
+- return (None, None, None, None, None, None)
++ return (None, None, None, None, None, None), to_close
+
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+@@ -835,6 +830,10 @@ class Popen(object):
+ # Assuming file-like object
+ p2cread = msvcrt.get_osfhandle(stdin.fileno())
+ p2cread = self._make_inheritable(p2cread)
++ # We just duplicated the handle, it has to be closed at the end
++ to_close.add(p2cread)
++ if stdin == PIPE:
++ to_close.add(p2cwrite)
+
+ if stdout is None:
+ c2pwrite = _subprocess.GetStdHandle(_subprocess.STD_OUTPUT_HANDLE)
+@@ -848,6 +847,10 @@ class Popen(object):
+ # Assuming file-like object
+ c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+ c2pwrite = self._make_inheritable(c2pwrite)
++ # We just duplicated the handle, it has to be closed at the end
++ to_close.add(c2pwrite)
++ if stdout == PIPE:
++ to_close.add(c2pread)
+
+ if stderr is None:
+ errwrite = _subprocess.GetStdHandle(_subprocess.STD_ERROR_HANDLE)
+@@ -863,10 +866,14 @@ class Popen(object):
+ # Assuming file-like object
+ errwrite = msvcrt.get_osfhandle(stderr.fileno())
+ errwrite = self._make_inheritable(errwrite)
++ # We just duplicated the handle, it has to be closed at the end
++ to_close.add(errwrite)
++ if stderr == PIPE:
++ to_close.add(errread)
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+- errread, errwrite)
++ errread, errwrite), to_close
+
+
+ def _make_inheritable(self, handle):
+@@ -895,7 +902,7 @@ class Popen(object):
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+- startupinfo, creationflags, shell,
++ startupinfo, creationflags, shell, to_close,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+@@ -934,6 +941,10 @@ class Popen(object):
+ # kill children.
+ creationflags |= _subprocess.CREATE_NEW_CONSOLE
+
++ def _close_in_parent(fd):
++ fd.Close()
++ to_close.remove(fd)
++
+ # Start the process
+ try:
+ hp, ht, pid, tid = _subprocess.CreateProcess(executable, args,
+@@ -958,11 +969,11 @@ class Popen(object):
+ # pipe will not close when the child process exits and the
+ # ReadFile will hang.
+ if p2cread is not None:
+- p2cread.Close()
++ _close_in_parent(p2cread)
+ if c2pwrite is not None:
+- c2pwrite.Close()
++ _close_in_parent(c2pwrite)
+ if errwrite is not None:
+- errwrite.Close()
++ _close_in_parent(errwrite)
+
+ # Retain the process handle, but close the thread handle
+ self._child_created = True
+@@ -1088,6 +1099,7 @@ class Popen(object):
+ """Construct and return tuple with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
++ to_close = set()
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+ errread, errwrite = None, None
+@@ -1096,6 +1108,7 @@ class Popen(object):
+ pass
+ elif stdin == PIPE:
+ p2cread, p2cwrite = self.pipe_cloexec()
++ to_close.update((p2cread, p2cwrite))
+ elif isinstance(stdin, int):
+ p2cread = stdin
+ else:
+@@ -1106,6 +1119,7 @@ class Popen(object):
+ pass
+ elif stdout == PIPE:
+ c2pread, c2pwrite = self.pipe_cloexec()
++ to_close.update((c2pread, c2pwrite))
+ elif isinstance(stdout, int):
+ c2pwrite = stdout
+ else:
+@@ -1116,6 +1130,7 @@ class Popen(object):
+ pass
+ elif stderr == PIPE:
+ errread, errwrite = self.pipe_cloexec()
++ to_close.update((errread, errwrite))
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif isinstance(stderr, int):
+@@ -1126,7 +1141,7 @@ class Popen(object):
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+- errread, errwrite)
++ errread, errwrite), to_close
+
+
+ def _set_cloexec_flag(self, fd, cloexec=True):
+@@ -1170,7 +1185,7 @@ class Popen(object):
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+- startupinfo, creationflags, shell,
++ startupinfo, creationflags, shell, to_close,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+@@ -1189,6 +1204,10 @@ class Popen(object):
+ if executable is None:
+ executable = args[0]
+
++ def _close_in_parent(fd):
++ os.close(fd)
++ to_close.remove(fd)
++
+ # For transferring possible exec failure from child to parent
+ # The first char specifies the exception type: 0 means
+ # OSError, 1 means some other error.
+@@ -1283,17 +1302,17 @@ class Popen(object):
+ # be sure the FD is closed no matter what
+ os.close(errpipe_write)
+
+- if p2cread is not None and p2cwrite is not None:
+- os.close(p2cread)
+- if c2pwrite is not None and c2pread is not None:
+- os.close(c2pwrite)
+- if errwrite is not None and errread is not None:
+- os.close(errwrite)
+-
+ # Wait for exec to fail or succeed; possibly raising exception
+ # Exception limited to 1M
+ data = _eintr_retry_call(os.read, errpipe_read, 1048576)
+ finally:
++ if p2cread is not None and p2cwrite is not None:
++ _close_in_parent(p2cread)
++ if c2pwrite is not None and c2pread is not None:
++ _close_in_parent(c2pwrite)
++ if errwrite is not None and errread is not None:
++ _close_in_parent(errwrite)
++
+ # be sure the FD is closed no matter what
+ os.close(errpipe_read)
+
+diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
+--- a/Lib/test/test_subprocess.py
++++ b/Lib/test/test_subprocess.py
+@@ -14,6 +14,10 @@ try:
+ import resource
+ except ImportError:
+ resource = None
++try:
++ import threading
++except ImportError:
++ threading = None
+
+ mswindows = (sys.platform == "win32")
+
+@@ -629,6 +633,36 @@ class ProcessTestCase(BaseTestCase):
+ if c.exception.errno not in (errno.ENOENT, errno.EACCES):
+ raise c.exception
+
++ @unittest.skipIf(threading is None, "threading required")
++ def test_double_close_on_error(self):
++ # Issue #18851
++ fds = []
++ def open_fds():
++ for i in range(20):
++ fds.extend(os.pipe())
++ time.sleep(0.001)
++ t = threading.Thread(target=open_fds)
++ t.start()
++ try:
++ with self.assertRaises(EnvironmentError):
++ subprocess.Popen(['nonexisting_i_hope'],
++ stdin=subprocess.PIPE,
++ stdout=subprocess.PIPE,
++ stderr=subprocess.PIPE)
++ finally:
++ t.join()
++ exc = None
++ for fd in fds:
++ # If a double close occurred, some of those fds will
++ # already have been closed by mistake, and os.close()
++ # here will raise.
++ try:
++ os.close(fd)
++ except OSError as e:
++ exc = e
++ if exc is not None:
++ raise exc
++
+ def test_handles_closed_on_exception(self):
+ # If CreateProcess exits with an error, ensure the
+ # duplicate output handles are released
+@@ -783,7 +817,7 @@ class POSIXProcessTestCase(BaseTestCase)
+
+ def _execute_child(
+ self, args, executable, preexec_fn, close_fds, cwd, env,
+- universal_newlines, startupinfo, creationflags, shell,
++ universal_newlines, startupinfo, creationflags, shell, to_close,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+@@ -791,7 +825,7 @@ class POSIXProcessTestCase(BaseTestCase)
+ subprocess.Popen._execute_child(
+ self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+- startupinfo, creationflags, shell,
++ startupinfo, creationflags, shell, to_close,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)