FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

bpo-45030: Fix integer overflow in __reduce__ of the range iterator (… · python/cpython@fecd17f · GitHub

Repository navigation

Commit fecd17f

Browse files
bpo-45030: Fix integer overflow in __reduce__ of the range iterator (GH-28000)
It happened with fast range iterator when the calculated stop = start + step * len was out of the C long range. (cherry picked from commit 936f6a1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent c967bd5 commit fecd17f

3 files changed

Lines changed: 27 additions & 18 deletions

File tree

‎Lib/test/test_range.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,14 @@ def test_pickling(self):
375375

376376
def test_iterator_pickling(self):
377377
testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1), (13, 21, 3),
378-
(-2, 2, 2), (2**31-3, 2**31-1), (2**33, 2**33+2),
379-
(2**63-3, 2**63-1), (2**65, 2**65+2)]
378+
(-2, 2, 2)]
379+
for M in 2**31, 2**63:
380+
testcases += [
381+
(M-3, M-1), (4*M, 4*M+2),
382+
(M-2, M-1, 2), (-M+1, -M, -2),
383+
(1, 2, M-1), (-1, -2, -M),
384+
(1, M-1, M-1), (-1, -M, -M),
385+
]
380386
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
381387
for t in testcases:
382388
with self.subTest(proto=proto, t=t):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix integer overflow in pickling and copying the range iterator.

‎Objects/rangeobject.c‎

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -895,22 +895,14 @@ get_len_of_range(long lo, long hi, long step)
895895
is not representable as a C long, OverflowError is raised. */
896896

897897
static PyObject *
898-
fast_range_iter(long start, long stop, long step)
898+
fast_range_iter(long start, long stop, long step, long len)
899899
{
900900
rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type);
901-
unsigned long ulen;
902901
if (it == NULL)
903902
return NULL;
904903
it->start = start;
905904
it->step = step;
906-
ulen = get_len_of_range(start, stop, step);
907-
if (ulen > (unsigned long)LONG_MAX) {
908-
Py_DECREF(it);
909-
PyErr_SetString(PyExc_OverflowError,
910-
"range too large to represent as a range_iterator");
911-
return NULL;
912-
}
913-
it->len = (long)ulen;
905+
it->len = len;
914906
it->index = 0;
915907
return (PyObject *)it;
916908
}
@@ -1071,7 +1063,7 @@ range_iter(PyObject *seq)
10711063
rangeobject *r = (rangeobject *)seq;
10721064
longrangeiterobject *it;
10731065
long lstart, lstop, lstep;
1074-
PyObject *int_it;
1066+
unsigned long ulen;
10751067

10761068
assert(PyRange_Check(seq));
10771069

@@ -1092,12 +1084,22 @@ range_iter(PyObject *seq)
10921084
PyErr_Clear();
10931085
goto long_range;
10941086
}
1095-
int_it = fast_range_iter(lstart, lstop, lstep);
1096-
if (int_it == NULL && PyErr_ExceptionMatches(PyExc_OverflowError)) {
1097-
PyErr_Clear();
1087+
ulen = get_len_of_range(lstart, lstop, lstep);
1088+
if (ulen > (unsigned long)LONG_MAX) {
10981089
goto long_range;
10991090
}
1100-
return (PyObject *)int_it;
1091+
/* check for potential overflow of lstart + ulen * lstep */
1092+
if (ulen) {
1093+
if (lstep > 0) {
1094+
if (lstop > LONG_MAX - (lstep - 1))
1095+
goto long_range;
1096+
}
1097+
else {
1098+
if (lstop < LONG_MIN + (-1 - lstep))
1099+
goto long_range;
1100+
}
1101+
}
1102+
return fast_range_iter(lstart, lstop, lstep, (long)ulen);
11011103

11021104
long_range:
11031105
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
@@ -1183,7 +1185,7 @@ range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
11831185

11841186
new_stop = lstart - lstep;
11851187
new_start = (long)(new_stop + ulen * lstep);
1186-
return fast_range_iter(new_start, new_stop, -lstep);
1188+
return fast_range_iter(new_start, new_stop, -lstep, (long)ulen);
11871189

11881190
long_range:
11891191
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL