Skip to content
Open
19 changes: 19 additions & 0 deletions Lib/test/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,25 @@ def test_iterator_setstate(self):
it.__setstate__(2**64 - 7)
self.assertEqual(list(it), [12, 10])

def test_iterator_invalid_setstate(self):

class I:
def __int__(self): return 1
def __index__(self): return 1
def __repr__(self): return "I()"

invalid_values = (1.0, I(), "")

for invalid_value in invalid_values:
invalid_msg = F"state must be an int, not "
ranges = (("range_iter", range(10, 100, 2)),
("longrange_iter", range(10, 2**65, 2)))
for name, rng in ranges:
with self.subTest(invalid_value=invalid_value, range_name=name):
it = iter(rng)
with self.assertRaisesRegex(TypeError, invalid_msg):
it.__setstate__(invalid_value)

def test_odd_bug(self):
# This used to raise a "SystemError: NULL result without error"
# because the range validation step was eating the exception
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Restict passing of non-integer object to the ``rangeiter.__setstate__``
and ``longrangeiter.__setstate__``. Patch by Sergey Miryanov.
10 changes: 10 additions & 0 deletions Objects/rangeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,11 @@ rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
static PyObject *
rangeiter_setstate(PyObject *op, PyObject *state)
{
if (!PyLong_CheckExact(state)) {
PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state);
return NULL;
}

_PyRangeIterObject *r = (_PyRangeIterObject*)op;
long index = PyLong_AsLong(state);
if (index == -1 && PyErr_Occurred())
Expand Down Expand Up @@ -1042,6 +1047,11 @@ longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
static PyObject *
longrangeiter_setstate(PyObject *op, PyObject *state)
{
if (!PyLong_CheckExact(state)) {
PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state);
return NULL;
}

longrangeiterobject *r = (longrangeiterobject*)op;
PyObject *zero = _PyLong_GetZero(); // borrowed reference
int cmp;
Expand Down
Loading