merge 3.2

This commit is contained in:
Benjamin Peterson 2011-07-03 16:27:41 -05:00
commit 536feac7f8
3 changed files with 51 additions and 4 deletions

View File

@ -582,6 +582,18 @@ class ExceptionTests(unittest.TestCase):
pass pass
self.assertEqual(sys.exc_info(), (None, None, None)) self.assertEqual(sys.exc_info(), (None, None, None))
def test_generator_doesnt_retain_old_exc(self):
def g():
self.assertIsInstance(sys.exc_info()[1], RuntimeError)
yield
self.assertEqual(sys.exc_info(), (None, None, None))
it = g()
try:
raise RuntimeError
except RuntimeError:
next(it)
self.assertRaises(StopIteration, next, it)
def test_generator_finalizing_and_exc_info(self): def test_generator_finalizing_and_exc_info(self):
# See #7173 # See #7173
def simple_gen(): def simple_gen():

View File

@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- When a generator yields, do not retain the caller's exception state on the
generator.
- Issue #12475: Prevent generators from leaking their exception state into the - Issue #12475: Prevent generators from leaking their exception state into the
caller's frame as they return for the last time. caller's frame as they return for the last time.

View File

@ -1141,6 +1141,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
f->f_exc_traceback = tmp; \ f->f_exc_traceback = tmp; \
} }
#define RESTORE_AND_CLEAR_EXC_STATE() \
{ \
PyObject *type, *value, *tb; \
type = tstate->exc_type; \
value = tstate->exc_value; \
tb = tstate->exc_traceback; \
tstate->exc_type = f->f_exc_type; \
tstate->exc_value = f->f_exc_value; \
tstate->exc_traceback = f->f_exc_traceback; \
f->f_exc_type = NULL; \
f->f_exc_value = NULL; \
f->f_exc_traceback = NULL; \
Py_XDECREF(type); \
Py_XDECREF(value); \
Py_XDECREF(tb); \
}
/* Start of code */ /* Start of code */
if (f == NULL) if (f == NULL)
@ -3001,10 +3018,25 @@ fast_block_end:
retval = NULL; retval = NULL;
fast_yield: fast_yield:
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
/* Put aside the current exception state and restore that of the /* The purpose of this block is to put aside the generator's exception
calling frame. */ state and restore that of the calling frame. If the current
SWAP_EXC_STATE(); exception state is from the caller, we clear the exception values
on the generator frame, so they are not swapped back in latter. The
origin of the current exception state is determined by checking for
except handler blocks, which we must be in iff a new exception
state came into existence in this frame. (An uncaught exception
would have why == WHY_EXCEPTION, and we wouldn't be here). */
int i;
for (i = 0; i < f->f_iblock; i++)
if (f->f_blockstack[i].b_type == EXCEPT_HANDLER)
break;
if (i == f->f_iblock)
/* We did not create this exception. */
RESTORE_AND_CLEAR_EXC_STATE()
else
SWAP_EXC_STATE()
}
if (tstate->use_tracing) { if (tstate->use_tracing) {
if (tstate->c_tracefunc) { if (tstate->c_tracefunc) {