Skip to content

Commit a3e9128

Browse files
Issue #13454: Fix a crash when deleting an iterator created by itertools.tee()
if all other iterators were very advanced before.
1 parent 2f2dd99 commit a3e9128

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

Lib/test/test_itertools.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,14 @@ def irange(n):
930930
del a
931931
self.assertRaises(ReferenceError, getattr, p, '__class__')
932932

933+
# Issue 13454: Crash when deleting backward iterator from tee()
934+
def test_tee_del_backward(self):
935+
forward, backward = tee(range(20000000))
936+
for i in forward:
937+
pass
938+
939+
del backward
940+
933941
def test_StopIteration(self):
934942
self.assertRaises(StopIteration, next, zip())
935943

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ Core and Builtins
202202
Library
203203
-------
204204

205+
- Issue #13454: Fix a crash when deleting an iterator created by itertools.tee()
206+
if all other iterators were very advanced before.
207+
205208
- Issue #12411: Fix to cgi.parse_multipart to correctly use bytes boundaries
206209
and bytes data. Patch by Jonas Wagner.
207210

Modules/itertoolsmodule.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,14 +401,31 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg)
401401
return 0;
402402
}
403403

404+
static void
405+
teedataobject_safe_decref(PyObject *obj)
406+
{
407+
while (obj && Py_TYPE(obj) == &teedataobject_type &&
408+
Py_REFCNT(obj) == 1) {
409+
PyObject *nextlink = ((teedataobject *)obj)->nextlink;
410+
((teedataobject *)obj)->nextlink = NULL;
411+
Py_DECREF(obj);
412+
obj = nextlink;
413+
}
414+
Py_XDECREF(obj);
415+
}
416+
404417
static int
405418
teedataobject_clear(teedataobject *tdo)
406419
{
407420
int i;
421+
PyObject *tmp;
422+
408423
Py_CLEAR(tdo->it);
409424
for (i=0 ; i<tdo->numread ; i++)
410425
Py_CLEAR(tdo->values[i]);
411-
Py_CLEAR(tdo->nextlink);
426+
tmp = tdo->nextlink;
427+
tdo->nextlink = NULL;
428+
teedataobject_safe_decref(tmp);
412429
return 0;
413430
}
414431

@@ -475,6 +492,8 @@ tee_next(teeobject *to)
475492

476493
if (to->index >= LINKCELLS) {
477494
link = teedataobject_jumplink(to->dataobj);
495+
if (link == NULL)
496+
return NULL;
478497
Py_DECREF(to->dataobj);
479498
to->dataobj = (teedataobject *)link;
480499
to->index = 0;

0 commit comments

Comments
 (0)