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.
This commit is contained in:
parent
c77eccd608
commit
83195c3f0c
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
-------
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue