diff --git a/tornado/gen.py b/tornado/gen.py index 506697d7b9..03d08ba651 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -354,6 +354,7 @@ def run(self): "finished without waiting for callbacks %r" % self.pending_callbacks) self.deactivate_stack_context() + self.deactivate_stack_context = None return except Exception: self.finished = True diff --git a/tornado/stack_context.py b/tornado/stack_context.py index e70fe53d8b..68950676f5 100644 --- a/tornado/stack_context.py +++ b/tornado/stack_context.py @@ -161,6 +161,7 @@ def __exit__(self, type, value, traceback): return self.exception_handler(type, value, traceback) finally: _state.contexts = self.old_contexts + self.old_contexts = None class NullContext(object): diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py index 4daad796c4..e168c18a7c 100644 --- a/tornado/test/gen_test.py +++ b/tornado/test/gen_test.py @@ -269,6 +269,28 @@ def outer(): initial_stack_depth = len(stack_context._state.contexts) self.run_gen(outer) + def test_stack_context_leak_exception(self): + # same as previous, but with a function that exits with an exception + from tornado import stack_context + + @gen.engine + def inner(callback): + yield gen.Task(self.io_loop.add_callback) + 1 / 0 + + @gen.engine + def outer(): + for i in xrange(10): + try: + yield gen.Task(inner) + except ZeroDivisionError: + pass + stack_increase = len(stack_context._state.contexts) - initial_stack_depth + self.assertTrue(stack_increase <= 2) + self.stop() + initial_stack_depth = len(stack_context._state.contexts) + self.run_gen(outer) + class GenSequenceHandler(RequestHandler): @asynchronous