summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-05-20 09:30:02 (GMT)
committerGitHub <noreply@github.com>2017-05-20 09:30:02 (GMT)
commit753bca3934a7618a4fa96e107ad1c5c18633a683 (patch)
treeabb5c023834c3d04d4a5deb7cfe0056dd5aea19b /Lib/test
parent763557eac06ba60d7c5133e4f80df8870d8f917e (diff)
downloadcpython-753bca3934a7618a4fa96e107ad1c5c18633a683.zip
cpython-753bca3934a7618a4fa96e107ad1c5c18633a683.tar.gz
cpython-753bca3934a7618a4fa96e107ad1c5c18633a683.tar.bz2
bpo-27945: Fixed various segfaults with dict. (#1657)
Based on patches by Duane Griffin and Tim Mitchell.
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_dict.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 832bb9c..8013f37 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -1085,6 +1085,91 @@ class DictTest(unittest.TestCase):
support.check_free_after_iterating(self, lambda d: iter(d.values()), dict)
support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
+ def test_equal_operator_modifying_operand(self):
+ # test fix for seg fault reported in issue 27945 part 3.
+ class X():
+ def __del__(self):
+ dict_b.clear()
+
+ def __eq__(self, other):
+ dict_a.clear()
+ return True
+
+ def __hash__(self):
+ return 13
+
+ dict_a = {X(): 0}
+ dict_b = {X(): X()}
+ self.assertTrue(dict_a == dict_b)
+
+ def test_fromkeys_operator_modifying_dict_operand(self):
+ # test fix for seg fault reported in issue 27945 part 4a.
+ class X(int):
+ def __hash__(self):
+ return 13
+
+ def __eq__(self, other):
+ if len(d) > 1:
+ d.clear()
+ return False
+
+ d = {} # this is required to exist so that d can be constructed!
+ d = {X(1): 1, X(2): 2}
+ try:
+ dict.fromkeys(d) # shouldn't crash
+ except RuntimeError: # implementation defined
+ pass
+
+ def test_fromkeys_operator_modifying_set_operand(self):
+ # test fix for seg fault reported in issue 27945 part 4b.
+ class X(int):
+ def __hash__(self):
+ return 13
+
+ def __eq__(self, other):
+ if len(d) > 1:
+ d.clear()
+ return False
+
+ d = {} # this is required to exist so that d can be constructed!
+ d = {X(1), X(2)}
+ try:
+ dict.fromkeys(d) # shouldn't crash
+ except RuntimeError: # implementation defined
+ pass
+
+ def test_dictitems_contains_use_after_free(self):
+ class X:
+ def __eq__(self, other):
+ d.clear()
+ return NotImplemented
+
+ d = {0: set()}
+ (0, X()) in d.items()
+
+ def test_init_use_after_free(self):
+ class X:
+ def __hash__(self):
+ pair[:] = []
+ return 13
+
+ pair = [X(), 123]
+ dict([pair])
+
+ def test_oob_indexing_dictiter_iternextitem(self):
+ class X(int):
+ def __del__(self):
+ d.clear()
+
+ d = {i: X(i) for i in range(8)}
+
+ def iter_and_mutate():
+ for result in d.items():
+ if result[0] == 2:
+ d[2] = None # free d[2] --> X(2).__del__ was called
+
+ self.assertRaises(RuntimeError, iter_and_mutate)
+
class CAPITest(unittest.TestCase):