]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
restore a generator's caller's exception state both on yield and (last) return
authorBenjamin Peterson <benjamin@python.org>
Sun, 3 Jul 2011 18:44:00 +0000 (13:44 -0500)
committerBenjamin Peterson <benjamin@python.org>
Sun, 3 Jul 2011 18:44:00 +0000 (13:44 -0500)
This prevents generator exception state from leaking into the caller.

Closes #12475.

Lib/test/test_exceptions.py
Misc/NEWS
Python/ceval.c

index 76f4249490f9105ed6fb752c5c42912e313e9127..ad9a19e6fd4102e9b9bbf2027ef6fab185387fdd 100644 (file)
@@ -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():
index e0aaa8d717c2aa9e44c8aa7e8f56e631e2d8abce..a05cc36aa398a9d7ca22b821a2bf06d33c91384e 100644 (file)
--- 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
 -------
 
index 705ed415a9ce36421ed9a77e4d732bd8a10d3d48..c0f2874a8f2398a26df2785ed8ee3dd834257f72 100644 (file)
@@ -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) {