Skip to content

Commit 83195c3

Browse files
committed
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.
1 parent c77eccd commit 83195c3

3 files changed

Lines changed: 23 additions & 4 deletions

File tree

Lib/test/test_exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,21 @@ def yield_raise():
566566
del g
567567
self.assertEqual(sys.exc_info()[0], TypeError)
568568

569+
def test_generator_leaking2(self):
570+
# See issue 12475.
571+
def g():
572+
yield
573+
try:
574+
raise RuntimeError
575+
except RuntimeError:
576+
it = g()
577+
next(it)
578+
try:
579+
next(it)
580+
except StopIteration:
581+
pass
582+
self.assertEqual(sys.exc_info(), (None, None, None))
583+
569584
def test_generator_finalizing_and_exc_info(self):
570585
# See #7173
571586
def simple_gen():

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.2.2?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #12475: Prevent generators from leaking their exception state into the
14+
callers frame as they return for the last time.
15+
1316
Library
1417
-------
1518

Python/ceval.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,10 +1881,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
18811881
retval = POP();
18821882
f->f_stacktop = stack_pointer;
18831883
why = WHY_YIELD;
1884-
/* Put aside the current exception state and restore
1885-
that of the calling frame. This only serves when
1886-
"yield" is used inside an except handler. */
1887-
SWAP_EXC_STATE();
18881884
goto fast_yield;
18891885

18901886
TARGET(POP_EXCEPT)
@@ -3021,6 +3017,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
30213017
retval = NULL;
30223018

30233019
fast_yield:
3020+
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN))
3021+
/* Put aside the current exception state and restore that of the
3022+
calling frame. */
3023+
SWAP_EXC_STATE();
3024+
30243025
if (tstate->use_tracing) {
30253026
if (tstate->c_tracefunc) {
30263027
if (why == WHY_RETURN || why == WHY_YIELD) {

0 commit comments

Comments
 (0)