]> granicus.if.org Git - python/commitdiff
bpo-29960 _random.Random corrupted on exception in setstate(). (#1019)
authorbladebryan <bryan.olson@acm.org>
Sat, 22 Apr 2017 06:10:46 +0000 (23:10 -0700)
committerSerhiy Storchaka <storchaka@gmail.com>
Sat, 22 Apr 2017 06:10:46 +0000 (09:10 +0300)
Lib/test/test_random.py
Misc/ACKS
Misc/NEWS
Modules/_randommodule.c

index 78909dd96eb7cbe23ec5a76e60658f8d3e11d2ce..48077fb5dbcc028627858d0838050a2acca0b9dd 100644 (file)
@@ -423,6 +423,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
@@ -436,6 +437,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
index d4f20c548f66d539e43dcb97ac3f85eef361eea2..ab41431add0fa53d097e716ea403ad4797fcb924 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1110,6 +1110,7 @@ Milan Oberkirch
 Pascal Oberndoerfer
 Jeffrey Ollie
 Adam Olsen
+Bryan Olson
 Grant Olson
 Koray Oner
 Piet van Oostrum
index fe1b0f839dcc59500683b24290d9206df7970d54..72fcded6a1551c30e2fd19d8814aa97081ba25d0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -317,6 +317,9 @@ Extension Modules
 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
   pass arguments of wrong type.
 
index 6db1d2dfe63925211ce03cfbfa03549cbd79f65a..9953654bdcb18b26d901f4b2495d714630bef207 100644 (file)
@@ -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;
 }