bpo-29960 _random.Random corrupted on exception in setstate(). (#1019)

This commit is contained in:
bladebryan 2017-04-21 23:10:46 -07:00 committed by Serhiy Storchaka
parent 1a5856bf92
commit 9616a82e78
4 changed files with 13 additions and 1 deletions

View File

@ -423,6 +423,7 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
def test_setstate_middle_arg(self): def test_setstate_middle_arg(self):
start_state = self.gen.getstate()
# Wrong type, s/b tuple # Wrong type, s/b tuple
self.assertRaises(TypeError, self.gen.setstate, (2, None, None)) self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
# Wrong length, s/b 625 # Wrong length, s/b 625
@ -436,6 +437,10 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.gen.setstate((2, (1,)*624+(625,), None)) self.gen.setstate((2, (1,)*624+(625,), None))
with self.assertRaises((ValueError, OverflowError)): with self.assertRaises((ValueError, OverflowError)):
self.gen.setstate((2, (1,)*624+(-1,), None)) 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)" # 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 # raise ValueError. I cannot think of a simple way to achieve this, so

View File

@ -1110,6 +1110,7 @@ Milan Oberkirch
Pascal Oberndoerfer Pascal Oberndoerfer
Jeffrey Ollie Jeffrey Ollie
Adam Olsen Adam Olsen
Bryan Olson
Grant Olson Grant Olson
Koray Oner Koray Oner
Piet van Oostrum Piet van Oostrum

View File

@ -317,6 +317,9 @@ Extension Modules
Library Library
------- -------
- bpo-29960: Preserve generator state when _random.Random.setstate()
raises an exception. Patch by Bryan Olson.
- bpo-29802: Fixed reference counting in module-level struct functions when - bpo-29802: Fixed reference counting in module-level struct functions when
pass arguments of wrong type. pass arguments of wrong type.

View File

@ -348,6 +348,7 @@ random_setstate(RandomObject *self, PyObject *state)
int i; int i;
unsigned long element; unsigned long element;
long index; long index;
uint32_t new_state[N];
if (!PyTuple_Check(state)) { if (!PyTuple_Check(state)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -364,7 +365,7 @@ random_setstate(RandomObject *self, PyObject *state)
element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i)); element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i));
if (element == (unsigned long)-1 && PyErr_Occurred()) if (element == (unsigned long)-1 && PyErr_Occurred())
return NULL; return NULL;
self->state[i] = (uint32_t)element; new_state[i] = (uint32_t)element;
} }
index = PyLong_AsLong(PyTuple_GET_ITEM(state, i)); index = PyLong_AsLong(PyTuple_GET_ITEM(state, i));
@ -375,6 +376,8 @@ random_setstate(RandomObject *self, PyObject *state)
return NULL; return NULL;
} }
self->index = (int)index; self->index = (int)index;
for (i = 0; i < N; i++)
self->state[i] = new_state[i];
Py_RETURN_NONE; Py_RETURN_NONE;
} }