From: Ben Darnell Date: Wed, 12 Jun 2013 03:32:40 +0000 (-0400) Subject: Set CLOEXEC on subprocess pipe endpoints so they are not inherited by the child. X-Git-Tag: v3.1.0~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3cf90980bc1f534229e3c63d241dcfedd38c8c4d;p=thirdparty%2Ftornado.git Set CLOEXEC on subprocess pipe endpoints so they are not inherited by the child. 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. --- diff --git a/tornado/process.py b/tornado/process.py index 438db66d2..5f05b1828 100644 --- a/tornado/process.py +++ b/tornado/process.py @@ -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) diff --git a/tornado/test/process_test.py b/tornado/test/process_test.py index 588488b95..5299a12a4 100644 --- a/tornado/test/process_test.py +++ b/tornado/test/process_test.py @@ -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')"],