def test_iterator_pickling(self):
testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1), (13, 21, 3),
- (-2, 2, 2), (2**31-3, 2**31-1), (2**33, 2**33+2),
- (2**63-3, 2**63-1), (2**65, 2**65+2)]
+ (-2, 2, 2)]
+ for M in 2**31, 2**63:
+ testcases += [
+ (M-3, M-1), (4*M, 4*M+2),
+ (M-2, M-1, 2), (-M+1, -M, -2),
+ (1, 2, M-1), (-1, -2, -M),
+ (1, M-1, M-1), (-1, -M, -M),
+ ]
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
for t in testcases:
with self.subTest(proto=proto, t=t):
is not representable as a C long, OverflowError is raised. */
static PyObject *
-fast_range_iter(long start, long stop, long step)
+fast_range_iter(long start, long stop, long step, long len)
{
rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type);
- unsigned long ulen;
if (it == NULL)
return NULL;
it->start = start;
it->step = step;
- ulen = get_len_of_range(start, stop, step);
- if (ulen > (unsigned long)LONG_MAX) {
- Py_DECREF(it);
- PyErr_SetString(PyExc_OverflowError,
- "range too large to represent as a range_iterator");
- return NULL;
- }
- it->len = (long)ulen;
+ it->len = len;
it->index = 0;
return (PyObject *)it;
}
rangeobject *r = (rangeobject *)seq;
longrangeiterobject *it;
long lstart, lstop, lstep;
- PyObject *int_it;
+ unsigned long ulen;
assert(PyRange_Check(seq));
PyErr_Clear();
goto long_range;
}
- int_it = fast_range_iter(lstart, lstop, lstep);
- if (int_it == NULL && PyErr_ExceptionMatches(PyExc_OverflowError)) {
- PyErr_Clear();
+ ulen = get_len_of_range(lstart, lstop, lstep);
+ if (ulen > (unsigned long)LONG_MAX) {
goto long_range;
}
- return (PyObject *)int_it;
+ /* check for potential overflow of lstart + ulen * lstep */
+ if (ulen) {
+ if (lstep > 0) {
+ if (lstop > LONG_MAX - (lstep - 1))
+ goto long_range;
+ }
+ else {
+ if (lstop < LONG_MIN + (-1 - lstep))
+ goto long_range;
+ }
+ }
+ return fast_range_iter(lstart, lstop, lstep, (long)ulen);
long_range:
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
new_stop = lstart - lstep;
new_start = (long)(new_stop + ulen * lstep);
- return fast_range_iter(new_start, new_stop, -lstep);
+ return fast_range_iter(new_start, new_stop, -lstep, (long)ulen);
long_range:
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);