]> granicus.if.org Git - python/commitdiff
Issue #12607: In subprocess, fix issue where if stdin, stdout or stderr is
authorRoss Lagerwall <rosslagerwall@gmail.com>
Wed, 27 Jul 2011 16:54:53 +0000 (18:54 +0200)
committerRoss Lagerwall <rosslagerwall@gmail.com>
Wed, 27 Jul 2011 16:54:53 +0000 (18:54 +0200)
given as a low fd, it gets overwritten.

Lib/subprocess.py
Lib/test/test_subprocess.py
Misc/NEWS

index ce08f83939cb51b39dcef8c20771685ab21f7841..e92961ab75be3ef18363409f924dd114f017de87 100644 (file)
@@ -1148,6 +1148,14 @@ class Popen(object):
                                 os.close(errread)
                             os.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:
+                                c2pwrite = os.dup(c2pwrite)
+                            if errwrite == 0 or errwrite == 1:
+                                errwrite = os.dup(errwrite)
+
                             # Dup fds for child
                             def _dup2(a, b):
                                 # dup2() removes the CLOEXEC flag but
index f1163562e7a92e1ac906ed278240f2cd188ea28f..477accf3356072f6c4b60aba2adcaf85b660a42a 100644 (file)
@@ -877,6 +877,64 @@ class POSIXProcessTestCase(BaseTestCase):
         # all standard fds closed.
         self.check_close_std_fds([0, 1, 2])
 
+    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 = test_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_wait_when_sigchild_ignored(self):
         # NOTE: sigchild_ignore.py may not be an effective test on all OSes.
         sigchild_ignore = test_support.findfile("sigchild_ignore.py",
index d2d0f89df1965ea13925fb94f694d20c9dbfff3c..c587f6ec6d1fc1f5c8b1054af0ba688726af3661 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -37,6 +37,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #12607: In subprocess, fix issue where if stdin, stdout or stderr is
+  given as a low fd, it gets overwritten.
+
 - Issue #12102: Document that buffered files must be flushed before being used
   with mmap. Patch by Steffen Daode Nurpmeso.