]> granicus.if.org Git - python/commitdiff
Issue #13454: Fix a crash when deleting an iterator created by itertools.tee()
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 25 Jan 2013 11:31:05 +0000 (13:31 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Fri, 25 Jan 2013 11:31:05 +0000 (13:31 +0200)
if all other iterators were very advanced before.

Lib/test/test_itertools.py
Misc/NEWS
Modules/itertoolsmodule.c

index ccdbf8abcbf2b10f753db49fbe1b67f3fd00a49b..6f933c56da13660db656c7aad8d38b0e6e38cdab 100644 (file)
@@ -906,6 +906,14 @@ class TestBasicOps(unittest.TestCase):
         del a
         self.assertRaises(ReferenceError, getattr, p, '__class__')
 
+    # Issue 13454: Crash when deleting backward iterator from tee()
+    def test_tee_del_backward(self):
+        forward, backward = tee(xrange(20000000))
+        for i in forward:
+            pass
+
+        del backward
+
     def test_StopIteration(self):
         self.assertRaises(StopIteration, izip().next)
 
index ce4f35ffa4141c7081bd70e4d713e468c5f75cf2..8d84806f28fd91df175710bfef4b44dda2f38354 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -189,6 +189,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #13454: Fix a crash when deleting an iterator created by itertools.tee()
+  if all other iterators were very advanced before.
+
 - Issue #1159051: GzipFile now raises EOFError when reading a corrupted file
   with truncated header or footer.
 
index f6d0e2335d955210047db767dbbb8991965cf0b5..ea822913662bf241f41ad2862857dfea61a54382 100644 (file)
@@ -401,14 +401,31 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg)
     return 0;
 }
 
+static void
+teedataobject_safe_decref(PyObject *obj)
+{
+    while (obj && Py_TYPE(obj) == &teedataobject_type &&
+           Py_REFCNT(obj) == 1) {
+        PyObject *nextlink = ((teedataobject *)obj)->nextlink;
+        ((teedataobject *)obj)->nextlink = NULL;
+        Py_DECREF(obj);
+        obj = nextlink;
+    }
+    Py_XDECREF(obj);
+}
+
 static int
 teedataobject_clear(teedataobject *tdo)
 {
     int i;
+    PyObject *tmp;
+
     Py_CLEAR(tdo->it);
     for (i=0 ; i<tdo->numread ; i++)
         Py_CLEAR(tdo->values[i]);
-    Py_CLEAR(tdo->nextlink);
+    tmp = tdo->nextlink;
+    tdo->nextlink = NULL;
+    teedataobject_safe_decref(tmp);
     return 0;
 }
 
@@ -475,6 +492,8 @@ tee_next(teeobject *to)
 
     if (to->index >= LINKCELLS) {
         link = teedataobject_jumplink(to->dataobj);
+        if (link == NULL)
+            return NULL;
         Py_DECREF(to->dataobj);
         to->dataobj = (teedataobject *)link;
         to->index = 0;