Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1365)

Side by Side Diff: Lib/test/test_hash.py

Issue 13703: Hash collision security issue
Patch Set: Created 1 year, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 # test the invariant that 1 # test the invariant that
2 # iff a==b then hash(a)==hash(b) 2 # iff a==b then hash(a)==hash(b)
3 # 3 #
4 # Also test that hash implementations are inherited as expected 4 # Also test that hash implementations are inherited as expected
5 5
6 import struct
6 import unittest 7 import unittest
7 from test import support 8 from test import support
9 from test.script_helper import assert_python_ok
8 from collections import Hashable 10 from collections import Hashable
11
12 IS_64BIT = (struct.calcsize('l') == 8)
9 13
10 14
11 class HashEqualityTestCase(unittest.TestCase): 15 class HashEqualityTestCase(unittest.TestCase):
12 16
13 def same_hash(self, *objlist): 17 def same_hash(self, *objlist):
14 # Hash each object given and fail if 18 # Hash each object given and fail if
15 # the hash values are not all the same. 19 # the hash values are not all the same.
16 hashed = list(map(hash, objlist)) 20 hashed = list(map(hash, objlist))
17 for h in hashed[1:]: 21 for h in hashed[1:]:
18 if h != hashed[0]: 22 if h != hashed[0]:
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 hashes_to_check = [range(10), 114 hashes_to_check = [range(10),
111 enumerate(range(10)), 115 enumerate(range(10)),
112 iter(DefaultIterSeq()), 116 iter(DefaultIterSeq()),
113 iter(lambda: 0, 0), 117 iter(lambda: 0, 0),
114 ] 118 ]
115 119
116 def test_hashes(self): 120 def test_hashes(self):
117 _default_hash = object.__hash__ 121 _default_hash = object.__hash__
118 for obj in self.hashes_to_check: 122 for obj in self.hashes_to_check:
119 self.assertEqual(hash(obj), _default_hash(obj)) 123 self.assertEqual(hash(obj), _default_hash(obj))
124
125 class RandomizationTestCase(unittest.TestCase):
126
127 # Examples of the various types having randomized hash:
128 test_reprs = [repr('abc'), repr(b'abc')]
129
130 def get_hash(self, repr_, randomization=None, seed=None):
131 env = {}
132 if randomization is not None:
133 env['PYTHONHASHRANDOMIZATION'] = str(randomization)
134 if seed is not None:
135 env['PYTHONHASHSEED'] = str(seed)
136 out = assert_python_ok(
137 '-c', 'print(hash(%s))' % repr_,
138 **env)
139 stdout = out[1].strip()
140 return int(stdout)
141
142 def test_empty_string(self):
143 self.assertEqual(hash(""), 0)
144 self.assertEqual(hash(b""), 0)
145
146 def test_null_hash(self):
147 # PYTHONHASHSEED=0 disables the randomized hash
148 if IS_64BIT:
149 known_hash_of_obj = 1453079729188098211
150 else:
151 known_hash_of_obj = -1600925533
152 for repr_ in self.test_reprs:
153 # Randomization is disabled by default:
154 self.assertEqual(self.get_hash(repr_), known_hash_of_obj)
155
156 # If enabled, it can still be disabled by setting the seed to 0:
157 self.assertEqual(self.get_hash(repr_, randomization=1, seed=0),
158 known_hash_of_obj)
159
160 def test_fixed_hash(self):
161 # test a fixed seed for the randomized hash
162 # Note that all types share the same values:
163 if IS_64BIT:
164 h = -4410911502303878509
165 else:
166 h = -206076799
167 for repr_ in self.test_reprs:
168 self.assertEqual(self.get_hash(repr_, randomization=1, seed=42),
169 h)
170
171 def test_randomized_hash(self):
172 # two runs should return different hashes
173 for repr_ in self.test_reprs:
174 run1 = self.get_hash(repr_, randomization=1)
175 run2 = self.get_hash(repr_, randomization=1)
176 self.assertNotEqual(run1, run2)
177
120 178
121 def test_main(): 179 def test_main():
122 support.run_unittest(HashEqualityTestCase, 180 support.run_unittest(HashEqualityTestCase,
123 HashInheritanceTestCase, 181 HashInheritanceTestCase,
124 HashBuiltinsTestCase) 182 HashBuiltinsTestCase,
183 RandomizationTestCase)
125 184
126 185
127 if __name__ == "__main__": 186 if __name__ == "__main__":
128 test_main() 187 test_main()
OLDNEW
« no previous file with comments | « Lib/test/regrtest.py ('k') | Lib/test/test_os.py » ('j') | Makefile.pre.in » ('J')

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7