From: Mariatta Date: Sat, 27 May 2017 14:19:40 +0000 (-0700) Subject: [3.5] bpo-29960 _random.Random corrupted on exception in setstate(). … (#1288) X-Git-Tag: v3.5.4rc1~125 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=440bc4f4b2690b99541e87bedfdb0dc4abbc0501;p=python [3.5] bpo-29960 _random.Random corrupted on exception in setstate(). … (#1288) (cherry picked from commit 9616a82e7802241a4b74cf7ae38d43c37bf66e48) --- diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index e80ed17a8c..83a663faf9 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -348,6 +348,7 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) def test_setstate_middle_arg(self): + start_state = self.gen.getstate() # Wrong type, s/b tuple self.assertRaises(TypeError, self.gen.setstate, (2, None, None)) # Wrong length, s/b 625 @@ -361,6 +362,10 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.gen.setstate((2, (1,)*624+(625,), None)) with self.assertRaises((ValueError, OverflowError)): self.gen.setstate((2, (1,)*624+(-1,), None)) + # Failed calls to setstate() should not have changed the state. + bits100 = self.gen.getrandbits(100) + self.gen.setstate(start_state) + self.assertEqual(self.gen.getrandbits(100), bits100) # Little trick to make "tuple(x % (2**32) for x in internalstate)" # raise ValueError. I cannot think of a simple way to achieve this, so diff --git a/Misc/ACKS b/Misc/ACKS index d91d9c1ee0..53f6879535 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1090,6 +1090,7 @@ Milan Oberkirch Pascal Oberndoerfer Jeffrey Ollie Adam Olsen +Bryan Olson Grant Olson Koray Oner Piet van Oostrum diff --git a/Misc/NEWS b/Misc/NEWS index 5aed87a30a..f399734c71 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,9 @@ Extension Modules Library ------- +- bpo-29960: Preserve generator state when _random.Random.setstate() + raises an exception. Patch by Bryan Olson. + - bpo-30414: multiprocessing.Queue._feed background running thread do not break from main loop on exception. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 9ce7882895..acb116d2bf 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -313,6 +313,7 @@ random_setstate(RandomObject *self, PyObject *state) int i; unsigned long element; long index; + PY_UINT32_T new_state[N]; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, @@ -329,7 +330,7 @@ random_setstate(RandomObject *self, PyObject *state) element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i)); if (element == (unsigned long)-1 && PyErr_Occurred()) return NULL; - self->state[i] = (PY_UINT32_T)element; + new_state[i] = (PY_UINT32_T)element; } index = PyLong_AsLong(PyTuple_GET_ITEM(state, i)); @@ -340,6 +341,8 @@ random_setstate(RandomObject *self, PyObject *state) return NULL; } self->index = (int)index; + for (i = 0; i < N; i++) + self->state[i] = new_state[i]; Py_INCREF(Py_None); return Py_None;