diff -r e55cc0834e9c Include/pyerrors.h --- a/Include/pyerrors.h Wed Apr 15 17:08:45 2015 -0400 +++ b/Include/pyerrors.h Wed Apr 15 17:36:25 2015 -0400 @@ -36,6 +36,12 @@ typedef struct { PyException_HEAD + PyObject *index; + PyObject *length; +} PyIndexErrorObject; + +typedef struct { + PyException_HEAD PyObject *encoding; PyObject *object; Py_ssize_t start; @@ -279,11 +285,14 @@ PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); #endif /* MS_WINDOWS */ -PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, - PyObject *); PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetIndexError(PyObject *, PyObject *, + PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetIndexErrorWithFormat( + const char *, Py_ssize_t, Py_ssize_t); + /* Export the old function so that the existing API remains available: */ PyAPI_FUNC(void) PyErr_BadInternalCall(void); PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno); diff -r e55cc0834e9c Objects/abstract.c --- a/Objects/abstract.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/abstract.c Wed Apr 15 17:36:25 2015 -0400 @@ -1528,7 +1528,9 @@ Py_ssize_t l = (*m->sq_length)(s); if (l < 0) return NULL; - i += l; + if (i + l >= 0) { + i += l; + } } } return m->sq_item(s, i); @@ -1575,7 +1577,9 @@ Py_ssize_t l = (*m->sq_length)(s); if (l < 0) return -1; - i += l; + if (i >= -l) { + i += l; + } } } return m->sq_ass_item(s, i, o); @@ -1602,7 +1606,9 @@ Py_ssize_t l = (*m->sq_length)(s); if (l < 0) return -1; - i += l; + if (i >= -l) { + i += l; + } } } return m->sq_ass_item(s, i, (PyObject *)NULL); diff -r e55cc0834e9c Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/bytearrayobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -402,12 +402,14 @@ static PyObject * bytearray_getitem(PyByteArrayObject *self, Py_ssize_t i) { + if (i < -Py_SIZE(self) || i >= Py_SIZE(self)) { + PyErr_SetIndexErrorWithFormat( + "bytearray index %zd out of range (len=%zd)", i, Py_SIZE(self)); + return NULL; + } if (i < 0) i += Py_SIZE(self); - if (i < 0 || i >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); - return NULL; - } + return PyLong_FromLong((unsigned char)(PyByteArray_AS_STRING(self)[i])); } @@ -419,15 +421,7 @@ if (i == -1 && PyErr_Occurred()) return NULL; - - if (i < 0) - i += PyByteArray_GET_SIZE(self); - - if (i < 0 || i >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); - return NULL; - } - return PyLong_FromLong((unsigned char)(PyByteArray_AS_STRING(self)[i])); + return bytearray_getitem(self, i); } else if (PySlice_Check(index)) { Py_ssize_t start, stop, step, slicelength, cur, i; @@ -606,21 +600,21 @@ { int ival; + if (i < -Py_SIZE(self) || i >= Py_SIZE(self)) { + PyErr_SetIndexErrorWithFormat( + "bytearray index %zd out of range (len=%zd)", i, Py_SIZE(self)); + return -1; + } if (i < 0) i += Py_SIZE(self); - if (i < 0 || i >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); - return -1; - } - if (value == NULL) return bytearray_setslice(self, i, i+1, NULL); if (!_getbytevalue(value, &ival)) return -1; - PyByteArray_AS_STRING(self)[i] = ival; + PyByteArray_AS_STRING(self)[i] = (char)ival; return 0; } @@ -637,28 +631,7 @@ if (i == -1 && PyErr_Occurred()) return -1; - if (i < 0) - i += PyByteArray_GET_SIZE(self); - - if (i < 0 || i >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); - return -1; - } - - if (values == NULL) { - /* Fall through to slice assignment */ - start = i; - stop = i + 1; - step = 1; - slicelen = 1; - } - else { - int ival; - if (!_getbytevalue(values, &ival)) - return -1; - buf[i] = (char)ival; - return 0; - } + return bytearray_setitem(self, i, values); } else if (PySlice_Check(index)) { if (PySlice_GetIndicesEx(index, @@ -2526,12 +2499,13 @@ "pop from empty bytearray"); return NULL; } + if (index < -Py_SIZE(self) || index >= Py_SIZE(self)) { + PyErr_SetIndexErrorWithFormat( + "pop index %zd out of range (len=%zd)", index, Py_SIZE(self)); + return NULL; + } if (index < 0) index += Py_SIZE(self); - if (index < 0 || index >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "pop index out of range"); - return NULL; - } if (!_canresize(self)) return NULL; diff -r e55cc0834e9c Objects/bytesobject.c --- a/Objects/bytesobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/bytesobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -1388,7 +1388,8 @@ bytes_item(PyBytesObject *a, Py_ssize_t i) { if (i < 0 || i >= Py_SIZE(a)) { - PyErr_SetString(PyExc_IndexError, "index out of range"); + PyErr_SetIndexErrorWithFormat( + "index %zd out of range (len=%zd)", i, Py_SIZE(a)); return NULL; } return PyLong_FromLong((unsigned char)a->ob_sval[i]); @@ -1510,14 +1511,9 @@ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - if (i < 0) + if (i < 0 && i >= -PyBytes_GET_SIZE(self)) i += PyBytes_GET_SIZE(self); - if (i < 0 || i >= PyBytes_GET_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, - "index out of range"); - return NULL; - } - return PyLong_FromLong((unsigned char)self->ob_sval[i]); + return bytes_item(self, i); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, cur, i; diff -r e55cc0834e9c Objects/exceptions.c --- a/Objects/exceptions.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/exceptions.c Wed Apr 15 17:36:25 2015 -0400 @@ -1462,8 +1462,77 @@ /* * IndexError extends LookupError */ -SimpleExtendsException(PyExc_LookupError, IndexError, - "Sequence index out of range."); +static int +IndexError_init(PyIndexErrorObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *index; + PyObject *length; + + if (kwds) { + GET_KWD(index); + GET_KWD(length); + } + + return BaseException_init((PyBaseExceptionObject *)self, args, kwds); +} + +static int +IndexError_clear(PyIndexErrorObject *self) +{ + Py_CLEAR(self->index); + Py_CLEAR(self->length); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +IndexError_dealloc(PyIndexErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + IndexError_clear(self); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static int +IndexError_traverse(PyIndexErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->index); + Py_VISIT(self->length); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyObject * +IndexError_str(PyIndexErrorObject *self) +{ + /* Use the provided index + length to generate a default error message. */ + if (PyTuple_GET_SIZE(self->args) == 0 && self->index != NULL) { + if (self->length) { + return PyUnicode_FromFormat("%S (len=%S)", + self->index, self->length); + } + else { + return PyObject_Repr(self->index); + } + } + return BaseException_str((PyBaseExceptionObject *)self); +} + +static PyMemberDef IndexError_members[] = { + {"index", T_OBJECT, offsetof(PyIndexErrorObject, index), 0, + PyDoc_STR("index")}, + {"length", T_OBJECT, offsetof(PyIndexErrorObject, length), 0, + PyDoc_STR("sequence length")}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef IndexError_methods[] = { + {NULL} +}; + +ComplexExtendsException(PyExc_LookupError, IndexError, + IndexError, 0 /* new */, + IndexError_methods, IndexError_members, + 0 /* getset */, IndexError_str, + "Sequence index out of range."); /* diff -r e55cc0834e9c Objects/listobject.c --- a/Objects/listobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/listobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -190,8 +190,6 @@ return Py_SIZE(op); } -static PyObject *indexerr = NULL; - PyObject * PyList_GetItem(PyObject *op, Py_ssize_t i) { @@ -200,13 +198,8 @@ return NULL; } if (i < 0 || i >= Py_SIZE(op)) { - if (indexerr == NULL) { - indexerr = PyUnicode_FromString( - "list index out of range"); - if (indexerr == NULL) - return NULL; - } - PyErr_SetObject(PyExc_IndexError, indexerr); + PyErr_SetIndexErrorWithFormat( + "List index %zd out of range (len=%zd)", i, Py_SIZE(op)); return NULL; } return ((PyListObject *)op) -> ob_item[i]; @@ -225,8 +218,9 @@ } if (i < 0 || i >= Py_SIZE(op)) { Py_XDECREF(newitem); - PyErr_SetString(PyExc_IndexError, - "list assignment index out of range"); + PyErr_SetIndexErrorWithFormat( + "list assignment index %zd out of range (len=%zd)", + i, Py_SIZE(op)); return -1; } p = ((PyListObject *)op) -> ob_item + i; @@ -415,13 +409,8 @@ list_item(PyListObject *a, Py_ssize_t i) { if (i < 0 || i >= Py_SIZE(a)) { - if (indexerr == NULL) { - indexerr = PyUnicode_FromString( - "list index out of range"); - if (indexerr == NULL) - return NULL; - } - PyErr_SetObject(PyExc_IndexError, indexerr); + PyErr_SetIndexErrorWithFormat( + "list index %zd out of range (len=%zd)", i, Py_SIZE(a)); return NULL; } Py_INCREF(a->ob_item[i]); @@ -732,8 +721,8 @@ { PyObject *old_value; if (i < 0 || i >= Py_SIZE(a)) { - PyErr_SetString(PyExc_IndexError, - "list assignment index out of range"); + PyErr_SetIndexErrorWithFormat( + "list assignment index %zd out of range (len=%zd)", i, Py_SIZE(a)); return -1; } if (v == NULL) @@ -926,7 +915,8 @@ if (i < 0) i += Py_SIZE(self); if (i < 0 || i >= Py_SIZE(self)) { - PyErr_SetString(PyExc_IndexError, "pop index out of range"); + PyErr_SetIndexErrorWithFormat( + "pop index %zd out of range (len=%zd)", i, Py_SIZE(self)); return NULL; } v = self->ob_item[i]; @@ -2406,7 +2396,7 @@ i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - if (i < 0) + if (i < 0 && i >= -PyList_GET_SIZE(self)) i += PyList_GET_SIZE(self); return list_item(self, i); } @@ -2458,7 +2448,7 @@ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return -1; - if (i < 0) + if (i < 0 && i >= -PyList_GET_SIZE(self)) i += PyList_GET_SIZE(self); return list_ass_item(self, i, value); } diff -r e55cc0834e9c Objects/rangeobject.c --- a/Objects/rangeobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/rangeobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -251,12 +251,35 @@ compute_range_item(rangeobject *r, PyObject *arg) { int cmp_result; - PyObject *i, *result; + PyObject *i, *result, *zero, *neg_length, *error_msg; - PyObject *zero = PyLong_FromLong(0); - if (zero == NULL) + /* PyLong equivalent to: + * if (arg < -r->length || arg >= r->length) { + * + * } + */ + neg_length = PyNumber_Negative(r->length); + if (neg_length == NULL) return NULL; + cmp_result = PyObject_RichCompareBool(arg, neg_length, Py_LT); + Py_DECREF(neg_length); + if (cmp_result == 0) { + cmp_result = PyObject_RichCompareBool(arg, r->length, Py_GE); + } + if (cmp_result == -1) { + return NULL; + } + if (cmp_result == 1) { + error_msg = PyUnicode_FromFormat( + "range object index %S out of range (len=%S)", arg, r->length); + if (error_msg) { + PyErr_SetIndexError(error_msg, arg, r->length); + Py_DECREF(error_msg); + } + return NULL; + } + /* PyLong equivalent to: * if (arg < 0) { * i = r->length + arg @@ -264,41 +287,21 @@ * i = arg * } */ + zero = PyLong_FromLong(0); + if (zero == NULL) + return NULL; + cmp_result = PyObject_RichCompareBool(arg, zero, Py_LT); - if (cmp_result == -1) { - Py_DECREF(zero); + Py_DECREF(zero); + if (cmp_result == -1) return NULL; - } if (cmp_result == 1) { - i = PyNumber_Add(r->length, arg); - if (!i) { - Py_DECREF(zero); - return NULL; - } + i = PyNumber_Add(r->length, arg); + if (!i) + return NULL; } else { - i = arg; - Py_INCREF(i); - } - - /* PyLong equivalent to: - * if (i < 0 || i >= r->length) { - * - * } - */ - cmp_result = PyObject_RichCompareBool(i, zero, Py_LT); - Py_DECREF(zero); - if (cmp_result == 0) { - cmp_result = PyObject_RichCompareBool(i, r->length, Py_GE); - } - if (cmp_result == -1) { - Py_DECREF(i); - return NULL; - } - if (cmp_result == 1) { - Py_DECREF(i); - PyErr_SetString(PyExc_IndexError, - "range object index out of range"); - return NULL; + i = arg; + Py_INCREF(i); } result = compute_item(r, i); diff -r e55cc0834e9c Objects/tupleobject.c --- a/Objects/tupleobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/tupleobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -140,7 +140,8 @@ return NULL; } if (i < 0 || i >= Py_SIZE(op)) { - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + PyErr_SetIndexErrorWithFormat( + "tuple index %zd out of range (len=%zd)", i, Py_SIZE(op)); return NULL; } return ((PyTupleObject *)op) -> ob_item[i]; @@ -158,8 +159,9 @@ } if (i < 0 || i >= Py_SIZE(op)) { Py_XDECREF(newitem); - PyErr_SetString(PyExc_IndexError, - "tuple assignment index out of range"); + PyErr_SetIndexErrorWithFormat( + "tuple assignment index %zd out of range (len=%zd)", + i, Py_SIZE(op)); return -1; } p = ((PyTupleObject *)op) -> ob_item + i; @@ -383,7 +385,8 @@ tupleitem(PyTupleObject *a, Py_ssize_t i) { if (i < 0 || i >= Py_SIZE(a)) { - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + PyErr_SetIndexErrorWithFormat( + "tuple index %zd out of range (len=%zd)", i, Py_SIZE(a)); return NULL; } Py_INCREF(a->ob_item[i]); @@ -703,7 +706,7 @@ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - if (i < 0) + if (i < 0 && i >= -PyTuple_GET_SIZE(self)) i += PyTuple_GET_SIZE(self); return tupleitem(self, i); } diff -r e55cc0834e9c Objects/unicodeobject.c --- a/Objects/unicodeobject.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Objects/unicodeobject.c Wed Apr 15 17:36:25 2015 -0400 @@ -3906,7 +3906,9 @@ return (Py_UCS4)-1; } if (index < 0 || index >= PyUnicode_GET_LENGTH(unicode)) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); + PyErr_SetIndexErrorWithFormat( + "string index %zd out of range (len=%zd)", + index, PyUnicode_GET_LENGTH(unicode)); return (Py_UCS4)-1; } data = PyUnicode_DATA(unicode); @@ -3923,7 +3925,9 @@ } assert(PyUnicode_IS_READY(unicode)); if (index < 0 || index >= PyUnicode_GET_LENGTH(unicode)) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); + PyErr_SetIndexErrorWithFormat( + "string index %zd out of range (len=%zd)", + index, PyUnicode_GET_LENGTH(unicode)); return -1; } if (unicode_check_modifiable(unicode)) @@ -11388,7 +11392,9 @@ return NULL; } if (index < 0 || index >= PyUnicode_GET_LENGTH(self)) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); + PyErr_SetIndexErrorWithFormat( + "string index %zd out of range (len=%zd)", + index, PyUnicode_GET_LENGTH(self)); return NULL; } kind = PyUnicode_KIND(self); @@ -13725,7 +13731,7 @@ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - if (i < 0) + if (i < 0 && i >= -PyUnicode_GET_LENGTH(self)) i += PyUnicode_GET_LENGTH(self); return unicode_getitem(self, i); } else if (PySlice_Check(item)) { diff -r e55cc0834e9c Python/errors.c --- a/Python/errors.c Wed Apr 15 17:08:45 2015 -0400 +++ b/Python/errors.c Wed Apr 15 17:36:25 2015 -0400 @@ -752,6 +752,67 @@ return NULL; } +PyObject * +PyErr_SetIndexError(PyObject *msg, PyObject *index, PyObject *length) +{ + PyObject *args, *kwargs, *error; + + if (msg == NULL) { + args = PyTuple_New(0); + } + else { + args = PyTuple_New(1); + if (args) { + Py_INCREF(msg); + PyTuple_SET_ITEM(args, 0, msg); + } + } + if (args == NULL) + return NULL; + + kwargs = PyDict_New(); + if (kwargs == NULL) { + Py_DECREF(args); + return NULL; + } + + if (index && PyDict_SetItemString(kwargs, "index", index) < 0) + goto done; + if (length && PyDict_SetItemString(kwargs, "length", length) < 0) + goto done; + + error = PyObject_Call(PyExc_IndexError, args, kwargs); + if (error) { + PyErr_SetObject((PyObject *)Py_TYPE(error), error); + Py_DECREF(error); + } + +done: + Py_DECREF(args); + Py_DECREF(kwargs); + return NULL; +} + +PyObject * +PyErr_SetIndexErrorWithFormat( + const char *format, + Py_ssize_t index, + Py_ssize_t length) +{ + PyObject *msg; + PyObject *result; + + msg = PyUnicode_FromFormat(format, index, length); + if (msg == NULL) + return NULL; + + result = PyErr_SetIndexError(msg, + PyLong_FromSsize_t(index), + PyLong_FromSsize_t(length)); + Py_DECREF(msg); + return result; +} + void _PyErr_BadInternalCall(const char *filename, int lineno) {