summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-03-30 17:43:06 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-03-30 17:43:06 (GMT)
commit14a7d6389fb453cca18d61bbe39deff7062bc66f (patch)
treed7e472d6fd44d7648ec2fd04dff7dd2c6ae7e393 /Lib
parentd524b705afd09bad3d097cb413eff342dd5a5982 (diff)
downloadcpython-14a7d6389fb453cca18d61bbe39deff7062bc66f.zip
cpython-14a7d6389fb453cca18d61bbe39deff7062bc66f.tar.gz
cpython-14a7d6389fb453cca18d61bbe39deff7062bc66f.tar.bz2
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.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/seq_tests.py5
-rw-r--r--Lib/test/test_bytes.py4
-rw-r--r--Lib/test/test_deque.py4
-rw-r--r--Lib/test/test_dict.py9
-rw-r--r--Lib/test/test_iter.py6
-rw-r--r--Lib/test/test_ordered_dict.py9
-rw-r--r--Lib/test/test_set.py3
-rw-r--r--Lib/test/test_support.py18
-rw-r--r--Lib/test/test_unicode.py5
9 files changed, 62 insertions, 1 deletions
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index f4673d4..f019e8d 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -4,6 +4,7 @@ Tests common to tuple, list and UserList.UserList
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)
@@ -402,3 +403,7 @@ class CommonTest(unittest.TestCase):
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)
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index 02fba38..82ad451 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -518,6 +518,10 @@ class BaseBytesTest(unittest.TestCase):
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
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index 13ea02f..b4efa65 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -669,6 +669,10 @@ class TestSubclassWithKwargs(unittest.TestCase):
# 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 = """
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 1c63fc0..4474c9b 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -681,6 +681,15 @@ class DictTest(unittest.TestCase):
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):
diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py
index bd1b32d..4495fa1 100644
--- a/Lib/test/test_iter.py
+++ b/Lib/test/test_iter.py
@@ -2,7 +2,8 @@
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),
@@ -921,6 +922,9 @@ class TestCase(unittest.TestCase):
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)
diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py
index 78b3e83..85e4841 100644
--- a/Lib/test/test_ordered_dict.py
+++ b/Lib/test/test_ordered_dict.py
@@ -267,6 +267,15 @@ class TestOrderedDict(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
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index d9ea098..6baaccf 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -340,6 +340,9 @@ class TestJointOps(unittest.TestCase):
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
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 956936f..85f9965 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -1659,3 +1659,21 @@ def strip_python_stderr(stderr):
"""
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])
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 63fb831..93224e1 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -1857,6 +1857,11 @@ class UnicodeTest(
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__)