mirror of https://github.com/python/cpython
Bug 1003935: xrange overflows
Added XXX comment about why the undocumented PyRange_New() API function is too broken to be worth the considerable pain of repairing. Changed range_new() to stop using PyRange_New(). This fixes a variety of bogus errors. Nothing in the core uses PyRange_New() now. Documented that xrange() is intended to be simple and fast, and that CPython restricts its arguments, and length of its result sequence, to native C longs. Added some tests that failed before the patch, and repaired a test that relied on a bogus OverflowError getting raised.
This commit is contained in:
parent
d976ab7caf
commit
feec4533e2
|
@ -1099,6 +1099,12 @@ It's a function
|
||||||
them) except when a very large range is used on a memory-starved
|
them) except when a very large range is used on a memory-starved
|
||||||
machine or when all of the range's elements are never used (such as
|
machine or when all of the range's elements are never used (such as
|
||||||
when the loop is usually terminated with \keyword{break}).
|
when the loop is usually terminated with \keyword{break}).
|
||||||
|
|
||||||
|
\note{\function{xrange()} is intended to be simple and fast.
|
||||||
|
Implementations may impose restrictions to achieve this.
|
||||||
|
The C implementation of Python restricts all arguments to
|
||||||
|
native C longs ("short" Python integers), and also requires
|
||||||
|
that that number of elements fit in a native C long.}
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
\begin{funcdesc}{zip}{\optional{seq1, \moreargs}}
|
\begin{funcdesc}{zip}{\optional{seq1, \moreargs}}
|
||||||
|
|
|
@ -48,10 +48,15 @@ class XrangeTest(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, xrange, 0, "spam")
|
self.assertRaises(TypeError, xrange, 0, "spam")
|
||||||
self.assertRaises(TypeError, xrange, 0, 42, "spam")
|
self.assertRaises(TypeError, xrange, 0, 42, "spam")
|
||||||
|
|
||||||
self.assertRaises(OverflowError, xrange, 0, sys.maxint, sys.maxint-1)
|
self.assertEqual(len(xrange(0, sys.maxint, sys.maxint-1)), 2)
|
||||||
|
|
||||||
self.assertRaises(OverflowError, xrange, -sys.maxint, sys.maxint)
|
self.assertRaises(OverflowError, xrange, -sys.maxint, sys.maxint)
|
||||||
self.assertRaises(OverflowError, xrange, 0, 2*sys.maxint)
|
self.assertRaises(OverflowError, xrange, 0, 2*sys.maxint)
|
||||||
|
|
||||||
|
self.assertEqual(len(xrange(-sys.maxint, sys.maxint, 2)),
|
||||||
|
sys.maxint)
|
||||||
|
self.assertRaises(OverflowError, xrange, -sys.maxint-1, sys.maxint, 2)
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test.test_support.run_unittest(XrangeTest)
|
test.test_support.run_unittest(XrangeTest)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,13 @@ typedef struct {
|
||||||
long len;
|
long len;
|
||||||
} rangeobject;
|
} rangeobject;
|
||||||
|
|
||||||
|
/* XXX PyRange_New should be deprecated. It's not documented. It's not
|
||||||
|
* used in the core. Its error-checking is akin to Swiss cheese: accepts
|
||||||
|
* step == 0; accepts len < 0; ignores that (len - 1) * step may overflow;
|
||||||
|
* raises a baffling "integer addition" exception if it thinks the last
|
||||||
|
* item is "too big"; and doesn't compute whether "last item is too big"
|
||||||
|
* correctly even if the multiplication doesn't overflow.
|
||||||
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
PyRange_New(long start, long len, long step, int reps)
|
PyRange_New(long start, long len, long step, int reps)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +86,7 @@ get_len_of_range(long lo, long hi, long step)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
|
rangeobject *obj;
|
||||||
long ilow = 0, ihigh = 0, istep = 1;
|
long ilow = 0, ihigh = 0, istep = 1;
|
||||||
long n;
|
long n;
|
||||||
|
|
||||||
|
@ -107,7 +115,14 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
"xrange() result has too many items");
|
"xrange() result has too many items");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return PyRange_New(ilow, n, istep, 1);
|
|
||||||
|
obj = PyObject_New(rangeobject, &PyRange_Type);
|
||||||
|
if (obj == NULL)
|
||||||
|
return NULL;
|
||||||
|
obj->start = ilow;
|
||||||
|
obj->len = n;
|
||||||
|
obj->step = istep;
|
||||||
|
return (PyObject *) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(range_doc,
|
PyDoc_STRVAR(range_doc,
|
||||||
|
|
Loading…
Reference in New Issue