From a3e9128aba49b99451b19b49982b7b48e4f7ffe6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Jan 2013 13:19:31 +0200 Subject: [PATCH] Issue #13454: Fix a crash when deleting an iterator created by itertools.tee() if all other iterators were very advanced before. --- Lib/test/test_itertools.py | 8 ++++++++ Misc/NEWS | 3 +++ Modules/itertoolsmodule.c | 21 ++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 8cdc597e58..66e307da5a 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -930,6 +930,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(range(20000000)) + for i in forward: + pass + + del backward + def test_StopIteration(self): self.assertRaises(StopIteration, next, zip()) diff --git a/Misc/NEWS b/Misc/NEWS index 147b57c0ce..4c95a12315 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -202,6 +202,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 #12411: Fix to cgi.parse_multipart to correctly use bytes boundaries and bytes data. Patch by Jonas Wagner. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 77e76fe588..574eb684cc 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -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 ; inumread ; 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; -- 2.40.0