summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2011-07-03 18:44:00 (GMT)
committerBenjamin Peterson <benjamin@python.org>2011-07-03 18:44:00 (GMT)
commit83195c3f0cffc571e265ca7e42cbbe1f27c792e1 (patch)
tree715fce3d966235a79e37a059c7060a2814e62e6b
parentc77eccd608a8a7d74980b2257a2d2721435f7415 (diff)
downloadcpython-83195c3f0cffc571e265ca7e42cbbe1f27c792e1.zip
cpython-83195c3f0cffc571e265ca7e42cbbe1f27c792e1.tar.gz
cpython-83195c3f0cffc571e265ca7e42cbbe1f27c792e1.tar.bz2
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.
-rw-r--r--Lib/test/test_exceptions.py15
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/ceval.c9
3 files changed, 23 insertions, 4 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 76f4249..ad9a19e 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 e0aaa8d..a05cc36 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 705ed41..c0f2874 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) {