mirror of https://github.com/python/cpython
merge 3.2
This commit is contained in:
commit
536feac7f8
|
@ -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():
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue