diff -r 1b2134a78c17 Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py Fri Dec 28 10:09:54 2012 +0200 +++ b/Lib/test/test_itertools.py Fri Dec 28 19:19:35 2012 +0200 @@ -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 1b2134a78c17 Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c Fri Dec 28 10:09:54 2012 +0200 +++ b/Modules/itertoolsmodule.c Fri Dec 28 19:19:35 2012 +0200 @@ -473,14 +473,31 @@ 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 ; inumread ; i++) Py_CLEAR(tdo->values[i]); - Py_CLEAR(tdo->nextlink); + tmp = tdo->nextlink; + tdo->nextlink = NULL; + teedataobject_safe_decref(tmp); return 0; } @@ -617,6 +634,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;