[Python-checkins] cpython (merge 3.2 -> default): Issue #12791: Break reference cycles early when a generator exits with an

antoine.pitrou python-checkins at python.org
Sat Aug 20 14:20:46 CEST 2011


http://hg.python.org/cpython/rev/7d390c3a83c6
changeset: 71981:7d390c3a83c6
parent: 71977:b09d07d1f696
parent: 71980:867ce75b885c
user: Antoine Pitrou <solipsis at pitrou.net>
date: Sat Aug 20 14:18:25 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
@@ -608,6 +608,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 #12773: Make __doc__ mutable on user-defined classes.
 
 - Issue #12766: Raise an ValueError when creating a class with a class variable
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

AltStyle によって変換されたページ (->オリジナル) /