@@ -9,41 +9,40 @@ typedef struct {
9
9
long len ;
10
10
} rangeobject ;
11
11
12
- /* Return number of items in range/xrange (lo, hi, step). step > 0
13
- * required. Return a value < 0 if & only if the true value is too
14
- * large to fit in a signed long.
12
+ /* Return number of items in range (lo, hi, step). step != 0
13
+ * required. The result always fits in an unsigned long.
15
14
*/
16
- static long
15
+ static unsigned long
17
16
get_len_of_range (long lo , long hi , long step )
18
17
{
19
- /* -------------------------------------------------------------
20
- If lo >= hi, the range is empty.
21
- Else if n values are in the range, the last one is
22
- lo + (n-1)*step, which must be <= hi-1. Rearranging,
23
- n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
24
- the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
25
- the RHS is non-negative and so truncation is the same as the
26
- floor. Letting M be the largest positive long, the worst case
27
- for the RHS numerator is hi=M, lo=-M-1, and then
28
- hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
29
- precision to compute the RHS exactly.
30
- ---------------------------------------------------------------*/
31
- long n = 0 ;
32
- if ( lo < hi ) {
33
- unsigned long uhi = ( unsigned long ) hi ;
34
- unsigned long ulo = ( unsigned long ) lo ;
35
- unsigned long diff = uhi - ulo - 1 ;
36
- n = ( long )( diff / (unsigned long ) step + 1 );
37
- }
38
- return n ;
18
+ /* -------------------------------------------------------------
19
+ If step > 0 and lo >= hi, or step < 0 and lo < = hi, the range is empty.
20
+ Else for step > 0, if n values are in the range, the last one is
21
+ lo + (n-1)*step, which must be <= hi-1. Rearranging,
22
+ n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
23
+ the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
24
+ the RHS is non-negative and so truncation is the same as the
25
+ floor. Letting M be the largest positive long, the worst case
26
+ for the RHS numerator is hi=M, lo=-M-1, and then
27
+ hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
28
+ precision to compute the RHS exactly. The analysis for step < 0
29
+ is similar.
30
+ ---------------------------------------------------------------*/
31
+ assert ( step != 0 );
32
+ if ( step > 0 && lo < hi )
33
+ return 1UL + ( hi - 1UL - lo ) / step ;
34
+ else if ( step < 0 && lo > hi )
35
+ return 1UL + ( lo - 1UL - hi ) / (0UL - step );
36
+ else
37
+ return 0UL ;
39
38
}
40
39
41
40
static PyObject *
42
41
range_new (PyTypeObject * type , PyObject * args , PyObject * kw )
43
42
{
44
43
rangeobject * obj ;
45
44
long ilow = 0 , ihigh = 0 , istep = 1 ;
46
- long n ;
45
+ unsigned long n ;
47
46
48
47
if (!_PyArg_NoKeywords ("xrange()" , kw ))
49
48
return NULL ;
@@ -64,11 +63,8 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
64
63
PyErr_SetString (PyExc_ValueError , "xrange() arg 3 must not be zero" );
65
64
return NULL ;
66
65
}
67
- if (istep > 0 )
68
- n = get_len_of_range (ilow , ihigh , istep );
69
- else
70
- n = get_len_of_range (ihigh , ilow , - istep );
71
- if (n < 0 ) {
66
+ n = get_len_of_range (ilow , ihigh , istep );
67
+ if (n > (unsigned long )LONG_MAX || (long )n > PY_SSIZE_T_MAX ) {
72
68
PyErr_SetString (PyExc_OverflowError ,
73
69
"xrange() result has too many items" );
74
70
return NULL ;
@@ -78,7 +74,7 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
78
74
if (obj == NULL )
79
75
return NULL ;
80
76
obj -> start = ilow ;
81
- obj -> len = n ;
77
+ obj -> len = ( long ) n ;
82
78
obj -> step = istep ;
83
79
return (PyObject * ) obj ;
84
80
}
@@ -98,7 +94,9 @@ range_item(rangeobject *r, Py_ssize_t i)
98
94
"xrange object index out of range" );
99
95
return NULL ;
100
96
}
101
- return PyInt_FromSsize_t (r -> start + i * r -> step );
97
+ /* do calculation entirely using unsigned longs, to avoid
98
+ undefined behaviour due to signed overflow. */
99
+ return PyInt_FromLong ((long )(r -> start + (unsigned long )i * r -> step ));
102
100
}
103
101
104
102
static Py_ssize_t
@@ -304,9 +302,21 @@ range_reverse(PyObject *seq)
304
302
len = ((rangeobject * )seq )-> len ;
305
303
306
304
it -> index = 0 ;
307
- it -> start = start + (len - 1 ) * step ;
308
- it -> step = - step ;
309
305
it -> len = len ;
306
+ /* the casts below guard against signed overflow by turning it
307
+ into unsigned overflow instead. The correctness of this
308
+ code still depends on conversion from unsigned long to long
309
+ wrapping modulo ULONG_MAX+1, which isn't guaranteed (see
310
+ C99 6.3.1.3p3) but seems to hold in practice for all
311
+ platforms we're likely to meet.
312
+
313
+ If step == LONG_MIN then we still end up with LONG_MIN
314
+ after negation; but this works out, since we've still got
315
+ the correct value modulo ULONG_MAX+1, and the range_item
316
+ calculation is also done modulo ULONG_MAX+1.
317
+ */
318
+ it -> start = (long )(start + (unsigned long )(len - 1 ) * step );
319
+ it -> step = (long )(- (unsigned long )step );
310
320
311
321
return (PyObject * )it ;
312
322
}
0 commit comments