From d8f59e26e3a8254c061a3efee03912aee68e22b3 Mon Sep 17 00:00:00 2001 From: bladebryan Date: Fri, 21 Apr 2017 23:10:46 -0700 Subject: [PATCH 1/2] [2.7] bpo-29960 _random.Random corrupted on exception in setstate(). (GH-1019). (cherry picked from commit 9616a82e7802241a4b74cf7ae38d43c37bf66e48) --- Lib/test/test_random.py | 5 +++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/_randommodule.c | 5 ++++- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index e4876fd0902e70..90d334a835a2a7 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -311,6 +311,7 @@ def test_setstate_first_arg(self): 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 @@ -324,6 +325,10 @@ def test_setstate_middle_arg(self): 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) def test_referenceImplementation(self): # Compare the python implementation with results from the original diff --git a/Misc/ACKS b/Misc/ACKS index b7b58a7b1c95b8..95be42717a0c09 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1021,6 +1021,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 e56af3a60c849b..c8ba45abefc581 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Extension Modules Library ------- +- bpo-29960: Preserve generator state when _random.Random.setstate() + raises an exception. Patch by Bryan Olson. + - bpo-30310: tkFont now supports unicode options (e.g. font family). - bpo-30414: multiprocessing.Queue._feed background running diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 4b9b0eb35d076b..0c58ec87fa7522 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -341,6 +341,7 @@ random_setstate(RandomObject *self, PyObject *state) int i; unsigned long element; long index; + uint32_t new_state[N]; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, @@ -357,7 +358,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] = element & 0xffffffffUL; /* Make sure we get sane state */ + new_state[i] = (uint32_t)element; } index = PyLong_AsLong(PyTuple_GET_ITEM(state, i)); @@ -368,6 +369,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; From bd8bc503d8854a58b0f07b63066c40442fc59979 Mon Sep 17 00:00:00 2001 From: Mariatta Wijaya Date: Fri, 26 May 2017 22:00:47 -0700 Subject: [PATCH 2/2] use unsigned long instead of uint32_t --- Modules/_randommodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 0c58ec87fa7522..852b810ae21955 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -341,7 +341,7 @@ random_setstate(RandomObject *self, PyObject *state) int i; unsigned long element; long index; - uint32_t new_state[N]; + unsigned long new_state[N]; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, @@ -358,7 +358,7 @@ random_setstate(RandomObject *self, PyObject *state) element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i)); if (element == (unsigned long)-1 && PyErr_Occurred()) return NULL; - new_state[i] = (uint32_t)element; + new_state[i] = element & 0xffffffffUL; /* Make sure we get sane state */ } index = PyLong_AsLong(PyTuple_GET_ITEM(state, i));