From 14ddd5ec299dcd41ec5d856ec919515bc6a9d08d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jan 2015 02:06:07 +0100 Subject: Python issue #23173: If an exception is raised during the creation of a subprocess, kill the subprocess (close pipes, kill and read the return status). Log an error in such case. --- asyncio/base_subprocess.py | 77 +++++++++++++++++++++++++++++++--------------- asyncio/subprocess.py | 12 ++++++-- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/asyncio/base_subprocess.py b/asyncio/base_subprocess.py index afc434d..0787ad7 100644 --- a/asyncio/base_subprocess.py +++ b/asyncio/base_subprocess.py @@ -96,32 +96,61 @@ class BaseSubprocessTransport(transports.SubprocessTransport): def kill(self): self._proc.kill() + def _kill_wait(self): + """Close pipes, kill the subprocess and read its return status. + + Function called when an exception is raised during the creation + of a subprocess. + """ + if self._loop.get_debug(): + logger.warning('Exception during subprocess creation, ' + 'kill the subprocess %r', + self, + exc_info=True) + + proc = self._proc + if proc.stdout: + proc.stdout.close() + if proc.stderr: + proc.stderr.close() + if proc.stdin: + proc.stdin.close() + try: + proc.kill() + except ProcessLookupError: + pass + proc.wait() + @coroutine def _post_init(self): - proc = self._proc - loop = self._loop - if proc.stdin is not None: - _, pipe = yield from loop.connect_write_pipe( - lambda: WriteSubprocessPipeProto(self, 0), - proc.stdin) - self._pipes[0] = pipe - if proc.stdout is not None: - _, pipe = yield from loop.connect_read_pipe( - lambda: ReadSubprocessPipeProto(self, 1), - proc.stdout) - self._pipes[1] = pipe - if proc.stderr is not None: - _, pipe = yield from loop.connect_read_pipe( - lambda: ReadSubprocessPipeProto(self, 2), - proc.stderr) - self._pipes[2] = pipe - - assert self._pending_calls is not None - - self._loop.call_soon(self._protocol.connection_made, self) - for callback, data in self._pending_calls: - self._loop.call_soon(callback, *data) - self._pending_calls = None + try: + proc = self._proc + loop = self._loop + if proc.stdin is not None: + _, pipe = yield from loop.connect_write_pipe( + lambda: WriteSubprocessPipeProto(self, 0), + proc.stdin) + self._pipes[0] = pipe + if proc.stdout is not None: + _, pipe = yield from loop.connect_read_pipe( + lambda: ReadSubprocessPipeProto(self, 1), + proc.stdout) + self._pipes[1] = pipe + if proc.stderr is not None: + _, pipe = yield from loop.connect_read_pipe( + lambda: ReadSubprocessPipeProto(self, 2), + proc.stderr) + self._pipes[2] = pipe + + assert self._pending_calls is not None + + self._loop.call_soon(self._protocol.connection_made, self) + for callback, data in self._pending_calls: + self._loop.call_soon(callback, *data) + self._pending_calls = None + except: + self._kill_wait() + raise def _call(self, cb, *data): if self._pending_calls is not None: diff --git a/asyncio/subprocess.py b/asyncio/subprocess.py index a8ad03c..d83442e 100644 --- a/asyncio/subprocess.py +++ b/asyncio/subprocess.py @@ -216,7 +216,11 @@ def create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, protocol_factory, cmd, stdin=stdin, stdout=stdout, stderr=stderr, **kwds) - yield from protocol.waiter + try: + yield from protocol.waiter + except: + transport._kill_wait() + raise return Process(transport, protocol, loop) @coroutine @@ -232,5 +236,9 @@ def create_subprocess_exec(program, *args, stdin=None, stdout=None, program, *args, stdin=stdin, stdout=stdout, stderr=stderr, **kwds) - yield from protocol.waiter + try: + yield from protocol.waiter + except: + transport._kill_wait() + raise return Process(transport, protocol, loop) -- cgit v1.2.1