import unittest
import sys
+from test import test_support as support
# Various iterables
# This is used for checking the constructor (here and in test_deque.py)
self.assertEqual(a.index(0, -4*sys.maxint, 4*sys.maxint), 2)
self.assertRaises(ValueError, a.index, 0, 4*sys.maxint,-4*sys.maxint)
self.assertRaises(ValueError, a.index, 2, 0, -10)
+
+ def test_free_after_iterating(self):
+ support.check_free_after_iterating(self, iter, self.type2test)
+ support.check_free_after_iterating(self, reversed, self.type2test)
self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith,
x, None, None, None)
+ def test_free_after_iterating(self):
+ test.test_support.check_free_after_iterating(self, iter, self.type2test)
+ test.test_support.check_free_after_iterating(self, reversed, self.type2test)
+
class ByteArrayTest(BaseBytesTest):
type2test = bytearray
# SF bug #1486663 -- this used to erroneously raise a TypeError
SubclassWithKwargs(newarg=1)
+ def test_free_after_iterating(self):
+ # For now, bypass tests that require slicing
+ self.skipTest("Exhausted deque iterator doesn't free a deque")
+
#==============================================================================
libreftest = """
self._tracked(MyDict())
+ def test_free_after_iterating(self):
+ test_support.check_free_after_iterating(self, iter, dict)
+ test_support.check_free_after_iterating(self, lambda d: d.iterkeys(), dict)
+ test_support.check_free_after_iterating(self, lambda d: d.itervalues(), dict)
+ test_support.check_free_after_iterating(self, lambda d: d.iteritems(), dict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewkeys()), dict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewvalues()), dict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewitems()), dict)
+
from test import mapping_tests
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
import unittest
from test.test_support import run_unittest, TESTFN, unlink, have_unicode, \
- check_py3k_warnings, cpython_only
+ check_py3k_warnings, cpython_only, \
+ check_free_after_iterating
# Test result of triple loop (too big to inline)
TRIPLETS = [(0, 0, 0), (0, 0, 1), (0, 0, 2),
lst.extend(gen())
self.assertEqual(len(lst), 760)
+ def test_free_after_iterating(self):
+ check_free_after_iterating(self, iter, SequenceClass, (0,))
+
def test_main():
run_unittest(TestCase)
items = [('a', 1), ('c', 3), ('b', 2)]
self.assertEqual(list(MyOD(items).items()), items)
+ def test_free_after_iterating(self):
+ test_support.check_free_after_iterating(self, iter, OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: d.iterkeys(), OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: d.itervalues(), OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: d.iteritems(), OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewkeys()), OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewvalues()), OrderedDict)
+ test_support.check_free_after_iterating(self, lambda d: iter(d.viewitems()), OrderedDict)
+
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
type2test = OrderedDict
gc.collect()
self.assertTrue(ref() is None, "Cycle was not collected")
+ def test_free_after_iterating(self):
+ test_support.check_free_after_iterating(self, iter, self.thetype)
+
class TestSet(TestJointOps):
thetype = set
"""
stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip()
return stderr
+
+
+def check_free_after_iterating(test, iter, cls, args=()):
+ class A(cls):
+ def __del__(self):
+ done[0] = True
+ try:
+ next(it)
+ except StopIteration:
+ pass
+
+ done = [False]
+ it = iter(A(*args))
+ # Issue 26494: Shouldn't crash
+ test.assertRaises(StopIteration, next, it)
+ # The sequence should be deallocated just after the end of iterating
+ gc_collect()
+ test.assertTrue(done[0])
unicode_encodedecimal(u"123" + s, "xmlcharrefreplace"),
'123' + exp)
+ def test_free_after_iterating(self):
+ test_support.check_free_after_iterating(self, iter, unicode)
+ test_support.check_free_after_iterating(self, reversed, unicode)
+
+
def test_main():
test_support.run_unittest(__name__)
Core and Builtins
-----------------
+- Issue #26494: Fixed crash on iterating exhausting iterators.
+ Affected classes are generic sequence iterators, iterators of bytearray,
+ list, tuple, set, frozenset, dict, OrderedDict and corresponding views.
+
- Issue #26581: If coding cookie is specified multiple times on a line in
Python source code file, only the first one is taken to account.
return item;
}
- Py_DECREF(seq);
it->it_seq = NULL;
+ Py_DECREF(seq);
return NULL;
}
return key;
fail:
- Py_DECREF(d);
di->di_dict = NULL;
+ Py_DECREF(d);
return NULL;
}
return value;
fail:
- Py_DECREF(d);
di->di_dict = NULL;
+ Py_DECREF(d);
return NULL;
}
return result;
fail:
- Py_DECREF(d);
di->di_dict = NULL;
+ Py_DECREF(d);
return NULL;
}
PyErr_ExceptionMatches(PyExc_StopIteration))
{
PyErr_Clear();
- Py_DECREF(seq);
it->it_seq = NULL;
+ Py_DECREF(seq);
}
return NULL;
}
return item;
}
- Py_DECREF(seq);
it->it_seq = NULL;
+ Py_DECREF(seq);
return NULL;
}
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--;
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;
}
return key;
fail:
- Py_DECREF(so);
si->si_set = NULL;
+ Py_DECREF(so);
return NULL;
}
return item;
}
- Py_DECREF(seq);
it->it_seq = NULL;
+ Py_DECREF(seq);
return NULL;
}