Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 536feac

Browse files
committed
merge 3.2
2 parents ffada78 + ac91341 commit 536feac

3 files changed

Lines changed: 51 additions & 4 deletions

File tree

Lib/test/test_exceptions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,18 @@ def g():
582582
pass
583583
self.assertEqual(sys.exc_info(), (None, None, None))
584584

585+
def test_generator_doesnt_retain_old_exc(self):
586+
def g():
587+
self.assertIsInstance(sys.exc_info()[1], RuntimeError)
588+
yield
589+
self.assertEqual(sys.exc_info(), (None, None, None))
590+
it = g()
591+
try:
592+
raise RuntimeError
593+
except RuntimeError:
594+
next(it)
595+
self.assertRaises(StopIteration, next, it)
596+
585597
def test_generator_finalizing_and_exc_info(self):
586598
# See #7173
587599
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.3 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- When a generator yields, do not retain the caller's exception state on the
14+
generator.
15+
1316
- Issue #12475: Prevent generators from leaking their exception state into the
1417
caller's frame as they return for the last time.
1518

Python/ceval.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
11411141
f->f_exc_traceback = tmp; \
11421142
}
11431143

1144+
#define RESTORE_AND_CLEAR_EXC_STATE() \
1145+
{ \
1146+
PyObject *type, *value, *tb; \
1147+
type = tstate->exc_type; \
1148+
value = tstate->exc_value; \
1149+
tb = tstate->exc_traceback; \
1150+
tstate->exc_type = f->f_exc_type; \
1151+
tstate->exc_value = f->f_exc_value; \
1152+
tstate->exc_traceback = f->f_exc_traceback; \
1153+
f->f_exc_type = NULL; \
1154+
f->f_exc_value = NULL; \
1155+
f->f_exc_traceback = NULL; \
1156+
Py_XDECREF(type); \
1157+
Py_XDECREF(value); \
1158+
Py_XDECREF(tb); \
1159+
}
1160+
11441161
/* Start of code */
11451162

11461163
if (f == NULL)
@@ -3001,10 +3018,25 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
30013018
retval = NULL;
30023019

30033020
fast_yield:
3004-
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN))
3005-
/* Put aside the current exception state and restore that of the
3006-
calling frame. */
3007-
SWAP_EXC_STATE();
3021+
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
3022+
/* The purpose of this block is to put aside the generator's exception
3023+
state and restore that of the calling frame. If the current
3024+
exception state is from the caller, we clear the exception values
3025+
on the generator frame, so they are not swapped back in latter. The
3026+
origin of the current exception state is determined by checking for
3027+
except handler blocks, which we must be in iff a new exception
3028+
state came into existence in this frame. (An uncaught exception
3029+
would have why == WHY_EXCEPTION, and we wouldn't be here). */
3030+
int i;
3031+
for (i = 0; i < f->f_iblock; i++)
3032+
if (f->f_blockstack[i].b_type == EXCEPT_HANDLER)
3033+
break;
3034+
if (i == f->f_iblock)
3035+
/* We did not create this exception. */
3036+
RESTORE_AND_CLEAR_EXC_STATE()
3037+
else
3038+
SWAP_EXC_STATE()
3039+
}
30083040

30093041
if (tstate->use_tracing) {
30103042
if (tstate->c_tracefunc) {

0 commit comments

Comments
 (0)