Commit c7d063cc authored by Stefan Behnel's avatar Stefan Behnel

fix negative slice indices

parent 306c3a71
...@@ -427,15 +427,15 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -427,15 +427,15 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i,
if (likely(m && m->sq_ass_item)) { if (likely(m && m->sq_ass_item)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (likely(l >= 0)) { if (likely(l >= 0)) {
i += l; i += l;
} else { } else {
// if length > max(Py_ssize_t), maybe the object can wrap around itself? // if length > max(Py_ssize_t), maybe the object can wrap around itself?
if (PyErr_ExceptionMatches(PyExc_OverflowError)) if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_Clear(); PyErr_Clear();
else else
return -1; return -1;
} }
} }
return m->sq_ass_item(o, i, (PyObject *)NULL); return m->sq_ass_item(o, i, (PyObject *)NULL);
} }
...@@ -476,6 +476,25 @@ static CYTHON_INLINE PyObject* __Pyx_PySequence_GetObjectSlice( ...@@ -476,6 +476,25 @@ static CYTHON_INLINE PyObject* __Pyx_PySequence_GetObjectSlice(
} else } else
cstop = PY_SSIZE_T_MAX; cstop = PY_SSIZE_T_MAX;
} }
if (unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) {
Py_ssize_t l = ms->sq_length(obj);
if (likely(l >= 0)) {
if (cstop < 0) {
cstop += l;
if (cstop < 0) cstop = 0;
}
if (cstart < 0) {
cstart += l;
if (cstart < 0) cstart = 0;
}
} 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 ms->sq_slice(obj, cstart, cstop); return ms->sq_slice(obj, cstart, cstop);
} }
#endif #endif
......
def f(obj1, obj2, obj3, obj4): def test_full(seq):
""" """
>>> l = [1,2,3,4] >>> l = [1,2,3,4]
>>> f(1, l, 2, 3) >>> test_full(l)
[1, 2, 3, 4] [1, 2, 3, 4]
>>> l == f(1, l, 2, 3) >>> l == test_full(l)
True True
>>> l is f(1, l, 2, 3) >>> l is test_full(l)
False False
>>> try: f(1, 42, 2, 3) >>> try: test_full(42)
... except TypeError: pass ... except TypeError: pass
""" """
obj1 = obj2[:] obj = seq[:]
return obj1 return obj
def g(obj1, obj2, obj3, obj4): def test_start(seq, start):
""" """
>>> g(1, [1,2,3,4], 2, 3) >>> test_start([1,2,3,4], 2)
[3, 4] [3, 4]
>>> try: g(1, 42, 2, 3) >>> test_start([1,2,3,4], 3)
[4]
>>> test_start([1,2,3,4], 4)
[]
>>> test_start([1,2,3,4], 8)
[]
>>> test_start([1,2,3,4], -3)
[2, 3, 4]
>>> test_start([1,2,3,4], -4)
[1, 2, 3, 4]
>>> test_start([1,2,3,4], -8)
[1, 2, 3, 4]
>>> test_start([1,2,3,4], 0)
[1, 2, 3, 4]
>>> try: test_start(42, 2, 3)
... except TypeError: pass ... except TypeError: pass
""" """
obj1 = obj2[obj3:] obj = seq[start:]
return obj1 return obj
def h(obj1, obj2, obj3, obj4): def test_stop(seq, stop):
""" """
>>> h(1, [1,2,3,4], 2, 3) >>> test_stop([1,2,3,4], 3)
[1, 2, 3] [1, 2, 3]
>>> try: h(1, 42, 2, 3) >>> test_stop([1,2,3,4], -1)
[1, 2, 3]
>>> test_stop([1,2,3,4], -3)
[1]
>>> test_stop([1,2,3,4], -4)
[]
>>> test_stop([1,2,3,4], -8)
[]
>>> test_stop([1,2,3,4], 0)
[]
>>> try: test_stop(42, 3)
... except TypeError: pass ... except TypeError: pass
""" """
obj1 = obj2[:obj4] obj = seq[:stop]
return obj1 return obj
def j(obj1, obj2, obj3, obj4): def test_start_and_stop(seq, start, stop):
""" """
>>> j(1, [1,2,3,4], 2, 3) >>> l = [1,2,3,4]
>>> test_start_and_stop(l, 2, 3)
[3] [3]
>>> try: j(1, 42, 2, 3) >>> test_start_and_stop(l, -3, -1)
[2, 3]
>>> try: test_start_and_stop(42, 2, 3)
... except TypeError: pass ... except TypeError: pass
""" """
obj1 = obj2[obj3:obj4] obj = seq[start:stop]
return obj1 return obj
class A(object): class A(object):
pass pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment