mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #12791: Break reference cycles early when a generator exits with an exception.
This commit is contained in:
parent
0c17d0d96e
commit
a370fcf3b2
3 changed files with 76 additions and 0 deletions
|
@ -607,6 +607,68 @@ class ExceptionTests(unittest.TestCase):
|
||||||
gc_collect()
|
gc_collect()
|
||||||
self.assertEqual(sys.exc_info(), (None, None, None))
|
self.assertEqual(sys.exc_info(), (None, None, None))
|
||||||
|
|
||||||
|
def _check_generator_cleanup_exc_state(self, testfunc):
|
||||||
|
# Issue #12791: exception state is cleaned up as soon as a generator
|
||||||
|
# is closed (reference cycles are broken).
|
||||||
|
class MyException(Exception):
|
||||||
|
def __init__(self, obj):
|
||||||
|
self.obj = obj
|
||||||
|
class MyObj:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def raising_gen():
|
||||||
|
try:
|
||||||
|
raise MyException(obj)
|
||||||
|
except MyException:
|
||||||
|
yield
|
||||||
|
|
||||||
|
obj = MyObj()
|
||||||
|
wr = weakref.ref(obj)
|
||||||
|
g = raising_gen()
|
||||||
|
next(g)
|
||||||
|
testfunc(g)
|
||||||
|
g = obj = None
|
||||||
|
obj = wr()
|
||||||
|
self.assertIs(obj, None)
|
||||||
|
|
||||||
|
def test_generator_throw_cleanup_exc_state(self):
|
||||||
|
def do_throw(g):
|
||||||
|
try:
|
||||||
|
g.throw(RuntimeError())
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
self._check_generator_cleanup_exc_state(do_throw)
|
||||||
|
|
||||||
|
def test_generator_close_cleanup_exc_state(self):
|
||||||
|
def do_close(g):
|
||||||
|
g.close()
|
||||||
|
self._check_generator_cleanup_exc_state(do_close)
|
||||||
|
|
||||||
|
def test_generator_del_cleanup_exc_state(self):
|
||||||
|
def do_del(g):
|
||||||
|
g = None
|
||||||
|
self._check_generator_cleanup_exc_state(do_del)
|
||||||
|
|
||||||
|
def test_generator_next_cleanup_exc_state(self):
|
||||||
|
def do_next(g):
|
||||||
|
try:
|
||||||
|
next(g)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.fail("should have raised StopIteration")
|
||||||
|
self._check_generator_cleanup_exc_state(do_next)
|
||||||
|
|
||||||
|
def test_generator_send_cleanup_exc_state(self):
|
||||||
|
def do_send(g):
|
||||||
|
try:
|
||||||
|
g.send(None)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.fail("should have raised StopIteration")
|
||||||
|
self._check_generator_cleanup_exc_state(do_send)
|
||||||
|
|
||||||
def test_3114(self):
|
def test_3114(self):
|
||||||
# Bug #3114: in its destructor, MyObject retrieves a pointer to
|
# Bug #3114: in its destructor, MyObject retrieves a pointer to
|
||||||
# obsolete and/or deallocated objects.
|
# obsolete and/or deallocated objects.
|
||||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.2.3?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #12791: Break reference cycles early when a generator exits with
|
||||||
|
an exception.
|
||||||
|
|
||||||
- Issue #12266: Fix str.capitalize() to correctly uppercase/lowercase
|
- Issue #12266: Fix str.capitalize() to correctly uppercase/lowercase
|
||||||
titlecased and cased non-letter characters.
|
titlecased and cased non-letter characters.
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,17 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
|
||||||
|
|
||||||
if (!result || f->f_stacktop == NULL) {
|
if (!result || f->f_stacktop == NULL) {
|
||||||
/* generator can't be rerun, so release the frame */
|
/* generator can't be rerun, so release the frame */
|
||||||
|
/* first clean reference cycle through stored exception traceback */
|
||||||
|
PyObject *t, *v, *tb;
|
||||||
|
t = f->f_exc_type;
|
||||||
|
v = f->f_exc_value;
|
||||||
|
tb = f->f_exc_traceback;
|
||||||
|
f->f_exc_type = NULL;
|
||||||
|
f->f_exc_value = NULL;
|
||||||
|
f->f_exc_traceback = NULL;
|
||||||
|
Py_XDECREF(t);
|
||||||
|
Py_XDECREF(v);
|
||||||
|
Py_XDECREF(tb);
|
||||||
Py_DECREF(f);
|
Py_DECREF(f);
|
||||||
gen->gi_frame = NULL;
|
gen->gi_frame = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue