diff options
author | Mark Dickinson <mdickinson@enthought.com> | 2012-06-30 16:19:35 (GMT) |
---|---|---|
committer | Mark Dickinson <mdickinson@enthought.com> | 2012-06-30 16:19:35 (GMT) |
commit | e0afb724020313d1d7ed0edf0662925bb74d995f (patch) | |
tree | 6193c1427ad4e8ffe311b56dafa864b680384550 | |
parent | 9848d812a386fd91536cdc252185ebae20e267c7 (diff) | |
download | cpython-e0afb724020313d1d7ed0edf0662925bb74d995f.zip cpython-e0afb724020313d1d7ed0edf0662925bb74d995f.tar.gz cpython-e0afb724020313d1d7ed0edf0662925bb74d995f.tar.bz2 |
Closes #14591: Random.jumpahead could produce an invalid MT state on 64-bit machines.
-rw-r--r-- | Lib/test/test_random.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_randommodule.c | 19 |
3 files changed, 28 insertions, 2 deletions
diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index df82990..caa4f28 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -57,6 +57,14 @@ class TestBasicOps(unittest.TestCase): self.assertRaises(TypeError, self.gen.jumpahead) # needs an arg self.assertRaises(TypeError, self.gen.jumpahead, 2, 3) # too many + def test_jumpahead_produces_valid_state(self): + # From http://bugs.python.org/issue14591. + self.gen.seed(199210368) + self.gen.jumpahead(13550674232554645900) + for i in range(500): + val = self.gen.random() + self.assertLess(val, 1.0) + def test_sample(self): # For the entire allowable range of 0 <= k <= N, validate that # the sample is of the correct length and contains only unique items @@ -75,6 +75,9 @@ Core and Builtins Library ------- +- Issue #14591: Fix bug in Random.jumpahead that could produce an invalid + Mersenne Twister state on 64-bit machines. + - Issue #5346: Preserve permissions of mbox, MMDF and Babyl mailbox files on flush(). diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 08c2277..8bb9e37 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -400,7 +400,7 @@ random_jumpahead(RandomObject *self, PyObject *n) long i, j; PyObject *iobj; PyObject *remobj; - unsigned long *mt, tmp; + unsigned long *mt, tmp, nonzero; if (!PyInt_Check(n) && !PyLong_Check(n)) { PyErr_Format(PyExc_TypeError, "jumpahead requires an " @@ -427,8 +427,23 @@ random_jumpahead(RandomObject *self, PyObject *n) mt[j] = tmp; } - for (i = 0; i < N; i++) + nonzero = 0; + for (i = 1; i < N; i++) { mt[i] += i+1; + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + nonzero |= mt[i]; + } + + /* Ensure the state is nonzero: in the unlikely event that mt[1] through + mt[N-1] are all zero, set the MSB of mt[0] (see issue #14591). In the + normal case, we fall back to the pre-issue 14591 behaviour for mt[0]. */ + if (nonzero) { + mt[0] += 1; + mt[0] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + } + else { + mt[0] = 0x80000000UL; + } self->index = N; Py_INCREF(Py_None); |