summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2016-08-31 22:01:08 (GMT)
committerRaymond Hettinger <python@rcn.com>2016-08-31 22:01:08 (GMT)
commitc7bab7cbf5d6a8b442f2ed3e23543cb4ee826c87 (patch)
tree5cb8f216dfd9a2ff8e034a618971f87f0ce287b2
parent4786787c07ba660c62a233ebfd16a8fcebc1c13e (diff)
downloadcpython-c7bab7cbf5d6a8b442f2ed3e23543cb4ee826c87.zip
cpython-c7bab7cbf5d6a8b442f2ed3e23543cb4ee826c87.tar.gz
cpython-c7bab7cbf5d6a8b442f2ed3e23543cb4ee826c87.tar.bz2
Issue #27706: Fix regression in random.seed(somestr, version=1)
-rw-r--r--Lib/random.py7
-rw-r--r--Lib/test/test_random.py18
-rw-r--r--Misc/NEWS5
3 files changed, 30 insertions, 0 deletions
diff --git a/Lib/random.py b/Lib/random.py
index 5950735..06513c8 100644
--- a/Lib/random.py
+++ b/Lib/random.py
@@ -112,6 +112,13 @@ class Random(_random.Random):
import time
a = int(time.time() * 256) # use fractional seconds
+ if version == 1 and isinstance(a, (str, bytes)):
+ x = ord(a[0]) << 7 if a else 0
+ for c in a:
+ x = ((1000003 * x) ^ ord(c)) & 0xFFFFFFFFFFFFFFFF
+ x ^= len(a)
+ a = -2 if x == -1 else x
+
if version == 2:
if isinstance(a, (str, bytes, bytearray)):
if isinstance(a, str):
diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py
index 5393431..e80ed17 100644
--- a/Lib/test/test_random.py
+++ b/Lib/test/test_random.py
@@ -326,6 +326,24 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4',
'0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1'])
+ def test_bug_27706(self):
+ # Verify that version 1 seeds are unaffected by hash randomization
+
+ self.gen.seed('nofar', version=1) # hash('nofar') == 5990528763808513177
+ self.assertEqual([self.gen.random().hex() for i in range(4)],
+ ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
+ '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
+
+ self.gen.seed('rachel', version=1) # hash('rachel') == -9091735575445484789
+ self.assertEqual([self.gen.random().hex() for i in range(4)],
+ ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
+ '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
+
+ self.gen.seed('', version=1) # hash('') == 0
+ self.assertEqual([self.gen.random().hex() for i in range(4)],
+ ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
+ '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
+
def test_setstate_first_arg(self):
self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
diff --git a/Misc/NEWS b/Misc/NEWS
index 129e124..731685f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -55,6 +55,11 @@ Library
- Issue #19884: Avoid spurious output on OS X with Gnu Readline.
+- Issue #27706: Restore deterministic behavior of random.Random().seed()
+ for string seeds using seeding version 1. Allows sequences of calls
+ to random() to exactly match those obtained in Python 2.
+ Patch by Nofar Schnider.
+
- Issue #10513: Fix a regression in Connection.commit(). Statements should
not be reset after a commit.