From d6a1a10f37ca9c1650958dcfe2812caaeebdc697 Mon Sep 17 00:00:00 2001 From: bry Date: Thu, 6 Apr 2017 22:39:26 -0700 Subject: [PATCH 1/2] Issue29960 _random.Random state corrupted on exception. --- Lib/test/test_random.py | 7 ++++++- Misc/NEWS | 3 +++ Modules/_randommodule.c | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 78909dd96eb7cb..169678bb628f48 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -423,6 +423,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 @@ -436,6 +437,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) # 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 @@ -446,7 +451,7 @@ def test_setstate_middle_arg(self): state_values[-1] = float('nan') state = (int(x) for x in state_values) self.assertRaises(TypeError, self.gen.setstate, (2, state, None)) - + def test_referenceImplementation(self): # Compare the python implementation with results from the original # code. Create 2000 53-bit precision random floats. Compare only diff --git a/Misc/NEWS b/Misc/NEWS index 396ada182e197b..a6fb60648fc178 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-29960: Preserve generator state when _random.Random.setstate() + raises an exception. Patch by Bryan Olson. + - bpo-29949: Fix memory usage regression of set and frozenset object. - bpo-29935: Fixed error messages in the index() method of tuple, list and deque diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 6db1d2dfe63925..9953654bdcb18b 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -348,6 +348,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, @@ -364,7 +365,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] = (uint32_t)element; + new_state[i] = (uint32_t)element; } index = PyLong_AsLong(PyTuple_GET_ITEM(state, i)); @@ -375,6 +376,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_RETURN_NONE; } From 0a2bca95c2664452b42348c8be4693e813bcb03b Mon Sep 17 00:00:00 2001 From: bry Date: Fri, 7 Apr 2017 00:10:57 -0700 Subject: [PATCH 2/2] bpo-29960 Fixed whitespace and attribution as per code review. --- Lib/test/test_random.py | 2 +- Misc/ACKS | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 169678bb628f48..48077fb5dbcc02 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -451,7 +451,7 @@ def test_setstate_middle_arg(self): state_values[-1] = float('nan') state = (int(x) for x in state_values) self.assertRaises(TypeError, self.gen.setstate, (2, state, None)) - + def test_referenceImplementation(self): # Compare the python implementation with results from the original # code. Create 2000 53-bit precision random floats. Compare only diff --git a/Misc/ACKS b/Misc/ACKS index 70678c3c2fe71a..c708d7ad7c9d9a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1108,6 +1108,7 @@ Milan Oberkirch Pascal Oberndoerfer Jeffrey Ollie Adam Olsen +Bryan Olson Grant Olson Koray Oner Piet van Oostrum