]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Set CLOEXEC on subprocess pipe endpoints so they are not inherited by the child.
authorBen Darnell <ben@bendarnell.com>
Wed, 12 Jun 2013 03:32:40 +0000 (23:32 -0400)
committerBen Darnell <ben@bendarnell.com>
Wed, 12 Jun 2013 03:32:40 +0000 (23:32 -0400)
This is what the subprocess module does when it creates pipes, and is
necessary so that a close of the writing side of the stdin pipe will
be recognized by the child process.

tornado/process.py
tornado/test/process_test.py

index 438db66d2f7009a155f242b1aa1faaeec224f47f..5f05b182820d70516df794328aaee91772a43c83 100644 (file)
@@ -33,6 +33,7 @@ from binascii import hexlify
 from tornado import ioloop
 from tornado.iostream import PipeIOStream
 from tornado.log import gen_log
+from tornado.platform.auto import set_close_exec
 from tornado import stack_context
 
 try:
@@ -69,6 +70,13 @@ def _reseed_random():
     random.seed(seed)
 
 
+def _pipe_cloexec():
+    r, w = os.pipe()
+    set_close_exec(r)
+    set_close_exec(w)
+    return r, w
+
+
 _task_id = None
 
 
@@ -184,17 +192,17 @@ class Subprocess(object):
         self.io_loop = kwargs.pop('io_loop', None)
         to_close = []
         if kwargs.get('stdin') is Subprocess.STREAM:
-            in_r, in_w = os.pipe()
+            in_r, in_w = _pipe_cloexec()
             kwargs['stdin'] = in_r
             to_close.append(in_r)
             self.stdin = PipeIOStream(in_w, io_loop=self.io_loop)
         if kwargs.get('stdout') is Subprocess.STREAM:
-            out_r, out_w = os.pipe()
+            out_r, out_w = _pipe_cloexec()
             kwargs['stdout'] = out_w
             to_close.append(out_w)
             self.stdout = PipeIOStream(out_r, io_loop=self.io_loop)
         if kwargs.get('stderr') is Subprocess.STREAM:
-            err_r, err_w = os.pipe()
+            err_r, err_w = _pipe_cloexec()
             kwargs['stderr'] = err_w
             to_close.append(err_w)
             self.stderr = PipeIOStream(err_r, io_loop=self.io_loop)
index 588488b95cbe5a2a369ae6408118cd78b5a2ceab..5299a12a479d57b302b631d7ba5836245107c731 100644 (file)
@@ -154,6 +154,20 @@ class SubprocessTest(AsyncTestCase):
         data = self.wait()
         self.assertEqual(data, b"")
 
+    def test_close_stdin(self):
+        # Close the parent's stdin handle and see that the child recognizes it.
+        subproc = Subprocess([sys.executable, '-u', '-i'],
+                             stdin=Subprocess.STREAM,
+                             stdout=Subprocess.STREAM, stderr=subprocess.STDOUT,
+                             io_loop=self.io_loop)
+        self.addCleanup(lambda: os.kill(subproc.pid, signal.SIGTERM))
+        subproc.stdout.read_until(b'>>> ', self.stop)
+        self.wait()
+        subproc.stdin.close()
+        subproc.stdout.read_until_close(self.stop)
+        data = self.wait()
+        self.assertEqual(data, b"\n")
+
     def test_stderr(self):
         subproc = Subprocess([sys.executable, '-u', '-c',
                               r"import sys; sys.stderr.write('hello\n')"],