From: Benjamin Peterson Date: Sun, 3 Jul 2011 18:44:00 +0000 (-0500) Subject: restore a generator's caller's exception state both on yield and (last) return X-Git-Tag: v3.2.2rc1~161 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=83195c3f0cffc571e265ca7e42cbbe1f27c792e1;p=thirdparty%2FPython%2Fcpython.git restore a generator's caller's exception state both on yield and (last) return This prevents generator exception state from leaking into the caller. Closes #12475. --- diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 76f4249490f9..ad9a19e6fd41 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -566,6 +566,21 @@ class ExceptionTests(unittest.TestCase): del g self.assertEqual(sys.exc_info()[0], TypeError) + def test_generator_leaking2(self): + # See issue 12475. + def g(): + yield + try: + raise RuntimeError + except RuntimeError: + it = g() + next(it) + try: + next(it) + except StopIteration: + pass + self.assertEqual(sys.exc_info(), (None, None, None)) + def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): diff --git a/Misc/NEWS b/Misc/NEWS index e0aaa8d717c2..a05cc36aa398 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.2.2? Core and Builtins ----------------- +- Issue #12475: Prevent generators from leaking their exception state into the + callers frame as they return for the last time. + Library ------- diff --git a/Python/ceval.c b/Python/ceval.c index 705ed415a9ce..c0f2874a8f23 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1881,10 +1881,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) retval = POP(); f->f_stacktop = stack_pointer; why = WHY_YIELD; - /* Put aside the current exception state and restore - that of the calling frame. This only serves when - "yield" is used inside an except handler. */ - SWAP_EXC_STATE(); goto fast_yield; TARGET(POP_EXCEPT) @@ -3021,6 +3017,11 @@ fast_block_end: retval = NULL; fast_yield: + if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) + /* Put aside the current exception state and restore that of the + calling frame. */ + SWAP_EXC_STATE(); + if (tstate->use_tracing) { if (tstate->c_tracefunc) { if (why == WHY_RETURN || why == WHY_YIELD) {