Skip to content

Commit 440bc4f

Browse files
authored
[3.5] bpo-29960 _random.Random corrupted on exception in setstate(). … (#1288)
(cherry picked from commit 9616a82)
1 parent a815b5a commit 440bc4f

File tree

4 files changed

+13
-1
lines changed

4 files changed

+13
-1
lines changed

‎Lib/test/test_random.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ def test_setstate_first_arg(self):
348348
self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
349349

350350
def test_setstate_middle_arg(self):
351+
start_state = self.gen.getstate()
351352
# Wrong type, s/b tuple
352353
self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
353354
# Wrong length, s/b 625
@@ -361,6 +362,10 @@ def test_setstate_middle_arg(self):
361362
self.gen.setstate((2, (1,)*624+(625,), None))
362363
with self.assertRaises((ValueError, OverflowError)):
363364
self.gen.setstate((2, (1,)*624+(-1,), None))
365+
# Failed calls to setstate() should not have changed the state.
366+
bits100 = self.gen.getrandbits(100)
367+
self.gen.setstate(start_state)
368+
self.assertEqual(self.gen.getrandbits(100), bits100)
364369

365370
# Little trick to make "tuple(x % (2**32) for x in internalstate)"
366371
# raise ValueError. I cannot think of a simple way to achieve this, so

‎Misc/ACKS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,7 @@ Milan Oberkirch
10901090
Pascal Oberndoerfer
10911091
Jeffrey Ollie
10921092
Adam Olsen
1093+
Bryan Olson
10931094
Grant Olson
10941095
Koray Oner
10951096
Piet van Oostrum

‎Misc/NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ Extension Modules
5656
Library
5757
-------
5858

59+
- bpo-29960: Preserve generator state when _random.Random.setstate()
60+
raises an exception. Patch by Bryan Olson.
61+
5962
- bpo-30414: multiprocessing.Queue._feed background running
6063
thread do not break from main loop on exception.
6164

‎Modules/_randommodule.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ random_setstate(RandomObject *self, PyObject *state)
313313
int i;
314314
unsigned long element;
315315
long index;
316+
PY_UINT32_T new_state[N];
316317

317318
if (!PyTuple_Check(state)) {
318319
PyErr_SetString(PyExc_TypeError,
@@ -329,7 +330,7 @@ random_setstate(RandomObject *self, PyObject *state)
329330
element = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(state, i));
330331
if (element == (unsigned long)-1 && PyErr_Occurred())
331332
return NULL;
332-
self->state[i] = (PY_UINT32_T)element;
333+
new_state[i] = (PY_UINT32_T)element;
333334
}
334335

335336
index = PyLong_AsLong(PyTuple_GET_ITEM(state, i));
@@ -340,6 +341,8 @@ random_setstate(RandomObject *self, PyObject *state)
340341
return NULL;
341342
}
342343
self->index = (int)index;
344+
for (i = 0; i < N; i++)
345+
self->state[i] = new_state[i];
343346

344347
Py_INCREF(Py_None);
345348
return Py_None;

0 commit comments

Comments
 (0)