diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2017-05-20 09:30:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-20 09:30:02 (GMT) |
commit | 753bca3934a7618a4fa96e107ad1c5c18633a683 (patch) | |
tree | abb5c023834c3d04d4a5deb7cfe0056dd5aea19b /Lib/test | |
parent | 763557eac06ba60d7c5133e4f80df8870d8f917e (diff) | |
download | cpython-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.py | 85 |
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): |