[Python-checkins] cpython (3.2): Issue #12791: Break reference cycles early when a generator exits with an
antoine.pitrou
python-checkins at python.org
Sat Aug 20 14:20:45 CEST 2011
http://hg.python.org/cpython/rev/867ce75b885c
changeset: 71980:867ce75b885c
branch: 3.2
parent: 71978:800d45e51dd7
user: Antoine Pitrou <solipsis at pitrou.net>
date: Sat Aug 20 14:15:03 2011 +0200
summary:
Issue #12791: Break reference cycles early when a generator exits with an exception.
files:
Lib/test/test_exceptions.py | 62 +++++++++++++++++++++++++
Misc/NEWS | 3 +
Objects/genobject.c | 11 ++++
3 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -607,6 +607,68 @@
gc_collect()
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):
# Bug #3114: in its destructor, MyObject retrieves a pointer to
# obsolete and/or deallocated objects.
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
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
titlecased and cased non-letter characters.
diff --git a/Objects/genobject.c b/Objects/genobject.c
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -100,6 +100,17 @@
if (!result || f->f_stacktop == NULL) {
/* 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);
gen->gi_frame = NULL;
}
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list