clean up GetItemInt code and fix negative indexing of objects with length > max(Py_ss...
authorStefan Behnel <stefan_ml@behnel.de>
Sat, 16 Mar 2013 09:26:07 +0000 (10:26 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Sat, 16 Mar 2013 09:26:07 +0000 (10:26 +0100)
Cython/Utility/ObjectHandling.c
tests/run/index.pyx

index b1345b2..7128030 100644 (file)
@@ -238,6 +238,27 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
 
 /////////////// GetItemInt.proto ///////////////
 
+#define __Pyx_GetItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
+    (((size) <= sizeof(Py_ssize_t)) ? \
+    __Pyx_GetItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
+    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+{{for type in ['List', 'Tuple']}}
+#define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
+    (((size) <= sizeof(Py_ssize_t)) ? \
+    __Pyx_GetItemInt_{{type}}_Fast(o, i, wraparound, boundscheck) : \
+    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i,
+                                                              int wraparound, int boundscheck);
+{{endfor}}
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j);
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
+                                                     int is_list, int wraparound, int boundscheck);
+
+/////////////// GetItemInt ///////////////
+
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
     PyObject *r;
     if (!j) return NULL;
@@ -247,11 +268,6 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
 }
 
 {{for type in ['List', 'Tuple']}}
-#define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
-    (((size) <= sizeof(Py_ssize_t)) ? \
-    __Pyx_GetItemInt_{{type}}_Fast(o, i, wraparound, boundscheck) : \
-    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
-
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i,
                                                               int wraparound, int boundscheck) {
 #if CYTHON_COMPILING_IN_CPYTHON
@@ -268,11 +284,6 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ss
 }
 {{endfor}}
 
-#define __Pyx_GetItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
-    (((size) <= sizeof(Py_ssize_t)) ? \
-    __Pyx_GetItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
-    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
-
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
                                                      int is_list, int wraparound, int boundscheck) {
 #if CYTHON_COMPILING_IN_CPYTHON
@@ -291,13 +302,20 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
             Py_INCREF(r);
             return r;
         }
-    } else {  /* inlined PySequence_GetItem() */
+    } else {  /* inlined PySequence_GetItem() + special cased length overflow */
         PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
         if (likely(m && m->sq_item)) {
             if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
                 Py_ssize_t l = m->sq_length(o);
-                if (unlikely(l < 0)) return NULL;
-                i += l;
+                if (likely(l >= 0)) {
+                    i += l;
+                } else {
+                    // if length > max(Py_ssize_t), maybe the object can wrap around itself?
+                    if (PyErr_ExceptionMatches(PyExc_OverflowError))
+                        PyErr_Clear();
+                    else
+                        return NULL;
+                }
             }
             return m->sq_item(o, i);
         }
index 4592380..c24d114 100644 (file)
@@ -9,6 +9,9 @@ import sys
 if sys.version_info < (2,5):
     __doc__ = __doc__.replace(u"'int' object ...", u'unsubscriptable object')
 
+cdef Py_ssize_t maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None))
+py_maxsize = maxsize
+
 import cython
 
 def index_tuple(tuple t, int i):
@@ -160,3 +163,39 @@ def large_literal_index(object o):
     True
     """
     return o[1000000000000000000000000000000]
+
+
+class LargeIndexable(object):
+    def __len__(self):
+        raise OverflowError
+
+    def __getitem__(self, index):
+        return index
+
+
+def test_large_indexing(obj):
+    """
+    >>> obj = LargeIndexable()
+    >>> zero, pone, none, pmaxsize, nmaxsize = test_large_indexing(obj)
+    >>> # , p2maxsize, n2maxsize
+    >>> zero
+    0
+    >>> pone
+    1
+    >>> none
+    -1
+    >>> pmaxsize == py_maxsize
+    True
+    >>> nmaxsize == -py_maxsize
+    True
+
+    #>>> p2maxsize == py_maxsize*2
+    #True
+    #>>> n2maxsize == -py_maxsize*2
+    #True
+    """
+    return (
+        obj[0], obj[1], obj[-1],
+        obj[maxsize], obj[-maxsize],
+        #obj[maxsize*2], obj[-maxsize*2]     # FIXME!
+    )