Patch #1538606, Patch to fix __index__() clipping.

I modified this patch some by fixing style, some error checking, and adding
XXX comments.  This patch requires review and some changes are to be expected.
I'm checking in now to get the greatest possible review and establish a
baseline for moving forward.  I don't want this to hold up release if possible.
This commit is contained in:
Neal Norwitz 2006-08-12 17:03:09 +00:00
parent f3e304297e
commit 8a87f5d37e
19 changed files with 321 additions and 236 deletions

View file

@ -8,8 +8,6 @@
#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
Py_TPFLAGS_CHECKTYPES)
#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
/* Shorthands to return certain errors */
@ -122,9 +120,9 @@ PyObject_GetItem(PyObject *o, PyObject *key)
return m->mp_subscript(o, key);
if (o->ob_type->tp_as_sequence) {
PyNumberMethods *nb = key->ob_type->tp_as_number;
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
Py_ssize_t key_value = nb->nb_index(key);
if (PyIndex_Check(key)) {
Py_ssize_t key_value;
key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (key_value == -1 && PyErr_Occurred())
return NULL;
return PySequence_GetItem(o, key_value);
@ -151,9 +149,9 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value)
return m->mp_ass_subscript(o, key, value);
if (o->ob_type->tp_as_sequence) {
PyNumberMethods *nb = key->ob_type->tp_as_number;
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
Py_ssize_t key_value = nb->nb_index(key);
if (PyIndex_Check(key)) {
Py_ssize_t key_value;
key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (key_value == -1 && PyErr_Occurred())
return -1;
return PySequence_SetItem(o, key_value, value);
@ -183,9 +181,9 @@ PyObject_DelItem(PyObject *o, PyObject *key)
return m->mp_ass_subscript(o, key, (PyObject*)NULL);
if (o->ob_type->tp_as_sequence) {
PyNumberMethods *nb = key->ob_type->tp_as_number;
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
Py_ssize_t key_value = nb->nb_index(key);
if (PyIndex_Check(key)) {
Py_ssize_t key_value;
key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (key_value == -1 && PyErr_Occurred())
return -1;
return PySequence_DelItem(o, key_value);
@ -653,9 +651,8 @@ static PyObject *
sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
{
Py_ssize_t count;
PyNumberMethods *nb = n->ob_type->tp_as_number;
if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) {
count = nb->nb_index(n);
if (PyIndex_Check(n)) {
count = PyNumber_AsSsize_t(n, PyExc_OverflowError);
if (count == -1 && PyErr_Occurred())
return NULL;
}
@ -938,23 +935,89 @@ int_from_string(const char *s, Py_ssize_t len)
return x;
}
/* Return a Py_ssize_t integer from the object item */
Py_ssize_t
/* Return a Python Int or Long from the object item
Raise TypeError if the result is not an int-or-long
or if the object cannot be interpreted as an index.
*/
PyObject *
PyNumber_Index(PyObject *item)
{
Py_ssize_t value = -1;
PyNumberMethods *nb = item->ob_type->tp_as_number;
if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
value = nb->nb_index(item);
PyObject *result = NULL;
if (item == NULL)
return null_error();
/* XXX(nnorwitz): should these be CheckExact? Aren't subclasses ok? */
if (PyInt_CheckExact(item) || PyLong_CheckExact(item)) {
Py_INCREF(item);
return item;
}
if (PyIndex_Check(item)) {
result = item->ob_type->tp_as_number->nb_index(item);
/* XXX(nnorwitz): Aren't subclasses ok here too? */
if (result &&
!PyInt_CheckExact(result) && !PyLong_CheckExact(result)) {
PyErr_Format(PyExc_TypeError,
"__index__ returned non-(int,long) " \
"(type %.200s)",
result->ob_type->tp_name);
Py_DECREF(result);
return NULL;
}
}
else {
PyErr_Format(PyExc_TypeError,
"'%.200s' object cannot be interpreted "
"as an index", item->ob_type->tp_name);
}
return value;
return result;
}
/* Return an error on Overflow only if err is not NULL*/
Py_ssize_t
PyNumber_AsSsize_t(PyObject *item, PyObject *err)
{
Py_ssize_t result;
PyObject *runerr;
PyObject *value = PyNumber_Index(item);
if (value == NULL)
return -1;
/* We're done if PyInt_AsSsize_t() returns without error. */
result = PyInt_AsSsize_t(value);
if (result != -1 || !(runerr = PyErr_Occurred()))
goto finish;
/* Error handling code -- only manage OverflowError differently */
if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
goto finish;
PyErr_Clear();
/* If no error-handling desired then the default clipping
is sufficient.
*/
if (!err) {
assert(PyLong_Check(value));
/* Whether or not it is less than or equal to
zero is determined by the sign of ob_size
*/
if (_PyLong_Sign(value) < 0)
result = PY_SSIZE_T_MIN;
else
result = PY_SSIZE_T_MAX;
}
else {
/* Otherwise replace the error with caller's error object. */
PyErr_Format(err,
"cannot fit '%.200s' into an index-sized integer",
item->ob_type->tp_name);
}
finish:
Py_DECREF(value);
return result;
}
PyObject *
PyNumber_Int(PyObject *o)
{