[Python-checkins] cpython (merge 3.2 -> default): Issue #12607: Merge with 3.2.

ross.lagerwall python-checkins at python.org
Wed Jul 27 07:47:16 CEST 2011


http://hg.python.org/cpython/rev/943d323cb4b8
changeset:   71525:943d323cb4b8
parent:      71522:dcfce522723d
parent:      71524:1140b32747c9
user:        Ross Lagerwall <rosslagerwall at gmail.com>
date:        Wed Jul 27 07:39:27 2011 +0200
summary:
  Issue #12607: Merge with 3.2.

files:
  Lib/test/test_subprocess.py |  58 +++++++++++++++++++++++++
  Misc/NEWS                   |   3 +
  Modules/_posixsubprocess.c  |   7 +++
  3 files changed, 68 insertions(+), 0 deletions(-)


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
@@ -1198,6 +1198,64 @@
             for fd in temp_fds:
                 os.close(fd)
 
+    def check_swap_fds(self, stdin_no, stdout_no, stderr_no):
+        # open up some temporary files
+        temps = [mkstemp() for i in range(3)]
+        temp_fds = [fd for fd, fname in temps]
+        try:
+            # unlink the files -- we won't need to reopen them
+            for fd, fname in temps:
+                os.unlink(fname)
+
+            # save a copy of the standard file descriptors
+            saved_fds = [os.dup(fd) for fd in range(3)]
+            try:
+                # duplicate the temp files over the standard fd's 0, 1, 2
+                for fd, temp_fd in enumerate(temp_fds):
+                    os.dup2(temp_fd, fd)
+
+                # write some data to what will become stdin, and rewind
+                os.write(stdin_no, b"STDIN")
+                os.lseek(stdin_no, 0, 0)
+
+                # now use those files in the given order, so that subprocess
+                # has to rearrange them in the child
+                p = subprocess.Popen([sys.executable, "-c",
+                    'import sys; got = sys.stdin.read();'
+                    'sys.stdout.write("got %s"%got); sys.stderr.write("err")'],
+                    stdin=stdin_no,
+                    stdout=stdout_no,
+                    stderr=stderr_no)
+                p.wait()
+
+                for fd in temp_fds:
+                    os.lseek(fd, 0, 0)
+
+                out = os.read(stdout_no, 1024)
+                err = support.strip_python_stderr(os.read(stderr_no, 1024))
+            finally:
+                for std, saved in enumerate(saved_fds):
+                    os.dup2(saved, std)
+                    os.close(saved)
+
+            self.assertEqual(out, b"got STDIN")
+            self.assertEqual(err, b"err")
+
+        finally:
+            for fd in temp_fds:
+                os.close(fd)
+
+    # When duping fds, if there arises a situation where one of the fds is
+    # either 0, 1 or 2, it is possible that it is overwritten (#12607).
+    # This tests all combinations of this.
+    def test_swap_fds(self):
+        self.check_swap_fds(0, 1, 2)
+        self.check_swap_fds(0, 2, 1)
+        self.check_swap_fds(1, 0, 2)
+        self.check_swap_fds(1, 2, 0)
+        self.check_swap_fds(2, 0, 1)
+        self.check_swap_fds(2, 1, 0)
+
     def test_surrogates_error_message(self):
         def prepare():
             raise ValueError("surrogate:\uDCff")
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -237,6 +237,9 @@
 Library
 -------
 
+- Issue #12607: In subprocess, fix issue where if stdin, stdout or stderr is
+  given as a low fd, it gets overwritten.
+
 - Issue #12590: IDLE editor window now always displays the first line
   when opening a long file.  With Tk 8.5, the first line was hidden.
 
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -69,6 +69,13 @@
     }
     POSIX_CALL(close(errpipe_read));
 
+    /* When duping fds, if there arises a situation where one of the fds is
+       either 0, 1 or 2, it is possible that it is overwritten (#12607). */
+    if (c2pwrite == 0)
+        POSIX_CALL(c2pwrite = dup(c2pwrite));
+    if (errwrite == 0 || errwrite == 1)
+        POSIX_CALL(errwrite = dup(errwrite));
+
     /* Dup fds for child.
        dup2() removes the CLOEXEC flag but we must do it ourselves if dup2()
        would be a no-op (issue #10806). */

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list