diff -r 40a1652349e9 Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py Sun Oct 14 22:16:27 2012 +0200 +++ b/Lib/test/test_itertools.py Mon Oct 15 09:50:50 2012 +0300 @@ -1267,6 +1267,14 @@ self.pickletest(a, compare=ans) self.pickletest(b, compare=ans) + # Issue 13454: Crash when deleting backward iterator from tee() + def test_tee_del_backward(self): + forward, backward = tee(range(20000000)) + for i in forward: + pass + + del backward + def test_StopIteration(self): self.assertRaises(StopIteration, next, zip()) diff -r 40a1652349e9 Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c Sun Oct 14 22:16:27 2012 +0200 +++ b/Modules/itertoolsmodule.c Mon Oct 15 09:50:50 2012 +0300 @@ -473,6 +473,19 @@ 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) { @@ -480,7 +493,8 @@ Py_CLEAR(tdo->it); for (i=0 ; inumread ; i++) Py_CLEAR(tdo->values[i]); - Py_CLEAR(tdo->nextlink); + teedataobject_safe_decref(tdo->nextlink); + tdo->nextlink = NULL; return 0; } @@ -617,6 +631,8 @@ 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;