diff -r a8589d88deb4 Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/support/__init__.py Sun Mar 06 20:23:53 2016 +0200 @@ -2432,3 +2432,22 @@ def run_in_subinterp(code): "memory allocations") import _testcapi return _testcapi.run_in_subinterp(code) + + +def check_free_after_iterating(test, iter, cls, args=()): + class A(cls): + def __del__(self): + nonlocal done + done = True + try: + next(it) + except StopIteration: + pass + + done = False + it = iter(A(*args)) + # Issue XXXXX: Shouldn't crash + test.assertRaises(StopIteration, next, it) + # The sequence should be deallocated just after the end of iterating + gc_collect() + test.assertTrue(done) diff -r a8589d88deb4 Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_bytes.py Sun Mar 06 20:23:53 2016 +0200 @@ -761,6 +761,10 @@ class BaseBytesTest: self.assertRaisesRegex(TypeError, r'\bendswith\b', b.endswith, x, None, None, None) + def test_free_after_iterating(self): + test.support.check_free_after_iterating(self, iter, self.type2test) + test.support.check_free_after_iterating(self, reversed, self.type2test) + class BytesTest(BaseBytesTest, unittest.TestCase): type2test = bytes diff -r a8589d88deb4 Lib/test/test_iter.py --- a/Lib/test/test_iter.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_iter.py Sun Mar 06 20:23:53 2016 +0200 @@ -3,6 +3,7 @@ import sys import unittest from test.support import run_unittest, TESTFN, unlink, cpython_only +from test.support import check_free_after_iterating import pickle import collections.abc @@ -980,6 +981,9 @@ class TestCase(unittest.TestCase): self.assertEqual(next(it), 0) self.assertEqual(next(it), 1) + def test_free_after_iterating(self): + check_free_after_iterating(self, iter, SequenceClass, (0,)) + def test_main(): run_unittest(TestCase) diff -r a8589d88deb4 Lib/test/test_list.py --- a/Lib/test/test_list.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_list.py Sun Mar 06 20:23:53 2016 +0200 @@ -151,5 +151,9 @@ class ListTest(list_tests.CommonTest): with self.assertRaises(TypeError): (3,) + L([1,2]) + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, list) + support.check_free_after_iterating(self, reversed, list) + if __name__ == "__main__": unittest.main() diff -r a8589d88deb4 Lib/test/test_set.py --- a/Lib/test/test_set.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_set.py Sun Mar 06 20:23:53 2016 +0200 @@ -364,6 +364,9 @@ class TestJointOps: gc.collect() self.assertTrue(ref() is None, "Cycle was not collected") + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, self.thetype) + class TestSet(TestJointOps, unittest.TestCase): thetype = set basetype = set diff -r a8589d88deb4 Lib/test/test_tuple.py --- a/Lib/test/test_tuple.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_tuple.py Sun Mar 06 20:23:53 2016 +0200 @@ -217,5 +217,9 @@ class TupleTest(seq_tests.CommonTest): self.assertLess(a, b) self.assertLess(b, c) + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, tuple) + support.check_free_after_iterating(self, reversed, tuple) + if __name__ == "__main__": unittest.main() diff -r a8589d88deb4 Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py Sun Mar 06 15:03:47 2016 +0200 +++ b/Lib/test/test_unicode.py Sun Mar 06 20:23:53 2016 +0200 @@ -2729,6 +2729,10 @@ class UnicodeTest(string_tests.CommonTes # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, str) + support.check_free_after_iterating(self, reversed, str) + class StringModuleTest(unittest.TestCase): def test_formatter_parser(self): diff -r a8589d88deb4 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Sun Mar 06 15:03:47 2016 +0200 +++ b/Objects/bytearrayobject.c Sun Mar 06 20:23:53 2016 +0200 @@ -3116,8 +3116,8 @@ bytearrayiter_next(bytesiterobject *it) return item; } + it->it_seq = NULL; Py_DECREF(seq); - it->it_seq = NULL; return NULL; } diff -r a8589d88deb4 Objects/bytesobject.c --- a/Objects/bytesobject.c Sun Mar 06 15:03:47 2016 +0200 +++ b/Objects/bytesobject.c Sun Mar 06 20:23:53 2016 +0200 @@ -3796,8 +3796,8 @@ striter_next(striterobject *it) return item; } + it->it_seq = NULL; Py_DECREF(seq); - it->it_seq = NULL; return NULL; } diff -r a8589d88deb4 Objects/listobject.c --- a/Objects/listobject.c Sun Mar 06 15:03:47 2016 +0200 +++ b/Objects/listobject.c Sun Mar 06 20:23:53 2016 +0200 @@ -2776,8 +2776,8 @@ listiter_next(listiterobject *it) return item; } + it->it_seq = NULL; Py_DECREF(seq); - it->it_seq = NULL; return NULL; } @@ -2906,9 +2906,17 @@ static PyObject * listreviter_next(listreviterobject *it) { PyObject *item; - Py_ssize_t index = it->it_index; - PyListObject *seq = it->it_seq; + Py_ssize_t index; + PyListObject *seq; + assert(it != NULL); + seq = it->it_seq; + if (seq == NULL) { + return NULL; + } + assert(PyList_Check(seq)); + + index = it->it_index; if (index>=0 && index < PyList_GET_SIZE(seq)) { item = PyList_GET_ITEM(seq, index); it->it_index--; @@ -2916,10 +2924,8 @@ listreviter_next(listreviterobject *it) return item; } it->it_index = -1; - if (seq != NULL) { - it->it_seq = NULL; - Py_DECREF(seq); - } + it->it_seq = NULL; + Py_DECREF(seq); return NULL; } diff -r a8589d88deb4 Objects/tupleobject.c --- a/Objects/tupleobject.c Sun Mar 06 15:03:47 2016 +0200 +++ b/Objects/tupleobject.c Sun Mar 06 20:23:53 2016 +0200 @@ -961,8 +961,8 @@ tupleiter_next(tupleiterobject *it) return item; } + it->it_seq = NULL; Py_DECREF(seq); - it->it_seq = NULL; return NULL; } diff -r a8589d88deb4 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Sun Mar 06 15:03:47 2016 +0200 +++ b/Objects/unicodeobject.c Sun Mar 06 20:23:53 2016 +0200 @@ -15401,8 +15401,8 @@ unicodeiter_next(unicodeiterobject *it) return item; } + it->it_seq = NULL; Py_DECREF(seq); - it->it_seq = NULL; return NULL; }