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

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
« no previous file with comments | « Lib/test/test_cmd_line.py ('k') | Lib/test/test_os.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 datetime
7 import os
8 import struct
6 import unittest 9 import unittest
7 from test import support 10 from test import support
11 from test.script_helper import assert_python_ok
8 from collections import Hashable 12 from collections import Hashable
13
14 IS_64BIT = (struct.calcsize('l') == 8)
9 15
10 16
11 class HashEqualityTestCase(unittest.TestCase): 17 class HashEqualityTestCase(unittest.TestCase):
12 18
13 def same_hash(self, *objlist): 19 def same_hash(self, *objlist):
14 # Hash each object given and fail if 20 # Hash each object given and fail if
15 # the hash values are not all the same. 21 # the hash values are not all the same.
16 hashed = list(map(hash, objlist)) 22 hashed = list(map(hash, objlist))
17 for h in hashed[1:]: 23 for h in hashed[1:]:
18 if h != hashed[0]: 24 if h != hashed[0]:
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 enumerate(range(10)), 117 enumerate(range(10)),
112 iter(DefaultIterSeq()), 118 iter(DefaultIterSeq()),
113 iter(lambda: 0, 0), 119 iter(lambda: 0, 0),
114 ] 120 ]
115 121
116 def test_hashes(self): 122 def test_hashes(self):
117 _default_hash = object.__hash__ 123 _default_hash = object.__hash__
118 for obj in self.hashes_to_check: 124 for obj in self.hashes_to_check:
119 self.assertEqual(hash(obj), _default_hash(obj)) 125 self.assertEqual(hash(obj), _default_hash(obj))
120 126
127 class HashRandomizationTests(unittest.TestCase):
128
129 # Each subclass should define a field "repr_", containing the repr() of
130 # an object to be tested
131
132 def get_hash_command(self, repr_):
133 return 'print(hash(%s))' % repr_
134
135 def get_hash(self, repr_, seed=None):
136 env = os.environ.copy()
137 env['__cleanenv'] = True # signal to assert_python not to do a copy
138 # of os.environ on its own
139 if seed is not None:
140 env['PYTHONHASHSEED'] = str(seed)
141 else:
142 env.pop('PYTHONHASHSEED', None)
143 out = assert_python_ok(
144 '-c', self.get_hash_command(repr_),
145 **env)
146 stdout = out[1].strip()
147 return int(stdout)
148
149 def test_randomized_hash(self):
150 # two runs should return different hashes
151 run1 = self.get_hash(self.repr_, seed='random')
152 run2 = self.get_hash(self.repr_, seed='random')
153 self.assertNotEqual(run1, run2)
154
155 class StringlikeHashRandomizationTests(HashRandomizationTests):
156 def test_null_hash(self):
157 # PYTHONHASHSEED=0 disables the randomized hash
158 if IS_64BIT:
159 known_hash_of_obj = 1453079729188098211
160 else:
161 known_hash_of_obj = -1600925533
162
163 # Randomization is disabled by default:
164 self.assertEqual(self.get_hash(self.repr_), known_hash_of_obj)
165
166 # It can also be disabled by setting the seed to 0:
167 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
168
169 def test_fixed_hash(self):
170 # test a fixed seed for the randomized hash
171 # Note that all types share the same values:
172 if IS_64BIT:
173 h = -4410911502303878509
174 else:
175 h = -206076799
176 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
177
178 class StrHashRandomizationTests(StringlikeHashRandomizationTests):
179 repr_ = repr('abc')
180
181 def test_empty_string(self):
182 self.assertEqual(hash(""), 0)
183
184 class BytesHashRandomizationTests(StringlikeHashRandomizationTests):
185 repr_ = repr(b'abc')
186
187 def test_empty_string(self):
188 self.assertEqual(hash(b""), 0)
189
190 class DatetimeTests(HashRandomizationTests):
191 def get_hash_command(self, repr_):
192 return 'import datetime; print(hash(%s))' % repr_
193
194 class DatetimeDateTests(DatetimeTests):
195 repr_ = repr(datetime.date(1066, 10, 14))
196
197 class DatetimeDatetimeTests(DatetimeTests):
198 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
199
200 class DatetimeTimeTests(DatetimeTests):
201 repr_ = repr(datetime.time(0))
202
203
121 def test_main(): 204 def test_main():
122 support.run_unittest(HashEqualityTestCase, 205 support.run_unittest(HashEqualityTestCase,
123 HashInheritanceTestCase, 206 HashInheritanceTestCase,
124 HashBuiltinsTestCase) 207 HashBuiltinsTestCase,
208 StrHashRandomizationTests,
209 BytesHashRandomizationTests,
210 DatetimeDateTests,
211 DatetimeDatetimeTests,
212 DatetimeTimeTests)
125 213
126 214
127 if __name__ == "__main__": 215 if __name__ == "__main__":
128 test_main() 216 test_main()
OLDNEW
« no previous file with comments | « Lib/test/test_cmd_line.py ('k') | Lib/test/test_os.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7