diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2009-01-03 16:59:18 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2009-01-03 16:59:18 (GMT) |
commit | c3b39245a7695cf39ba5524f59deeff52b00e5f9 (patch) | |
tree | 9736aa9a6d7c03b55eeb7d362a53f91d6000dda3 /Objects | |
parent | 8bcddcabd770dd424b97d7c667ef8e5337436215 (diff) | |
download | cpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.zip cpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.tar.gz cpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.tar.bz2 |
Issue #4580: slicing of memoryviews when itemsize != 1 is wrong.
Also fix len() to return number of items rather than length in bytes.
I'm sorry it was not possible for me to work on this without reindenting
a bit some stuff around. The indentation in memoryobject.c is a mess,
I'll open a separate bug for it.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/memoryobject.c | 131 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 2 |
2 files changed, 64 insertions, 69 deletions
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index f96fcbe..df89313 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -3,26 +3,31 @@ #include "Python.h" -static void -dup_buffer(Py_buffer *dest, Py_buffer *src) -{ - *dest = *src; - if (src->shape == &(src->len)) - dest->shape = &(dest->len); - if (src->strides == &(src->itemsize)) - dest->strides = &(dest->itemsize); -} - -/* XXX The buffer API should mandate that the shape array be non-NULL, but - it would complicate some code since the (de)allocation semantics of shape - are not specified. */ static Py_ssize_t get_shape0(Py_buffer *buf) { if (buf->shape != NULL) return buf->shape[0]; - assert(buf->ndim == 1 && buf->itemsize > 0); - return buf->len / buf->itemsize; + if (buf->ndim == 0) + return 1; + PyErr_SetString(PyExc_TypeError, + "exported buffer does not have any shape information associated " + "to it"); + return -1; +} + +static void +dup_buffer(Py_buffer *dest, Py_buffer *src) +{ + *dest = *src; + if (src->ndim == 1 && src->shape != NULL) { + dest->shape = &(dest->smalltable[0]); + dest->shape[0] = get_shape0(src); + } + if (src->ndim == 1 && src->strides != NULL) { + dest->strides = &(dest->smalltable[1]); + dest->strides[0] = src->strides[0]; + } } static int @@ -449,8 +454,6 @@ memory_tolist(PyMemoryViewObject *mem, PyObject *noargs) return res; } - - static PyMethodDef memory_methods[] = { {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL}, {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL}, @@ -474,19 +477,19 @@ memory_dealloc(PyMemoryViewObject *self) PyObject_CopyData(PyTuple_GET_ITEM(self->base,0), PyTuple_GET_ITEM(self->base,1)); - /* The view member should have readonly == -1 in - this instance indicating that the memory can - be "locked" and was locked and will be unlocked - again after this call. - */ - PyBuffer_Release(&(self->view)); - } - else { - PyBuffer_Release(&(self->view)); - } - Py_CLEAR(self->base); + /* The view member should have readonly == -1 in + this instance indicating that the memory can + be "locked" and was locked and will be unlocked + again after this call. + */ + PyBuffer_Release(&(self->view)); } - PyObject_GC_Del(self); + else { + PyBuffer_Release(&(self->view)); + } + Py_CLEAR(self->base); + } + PyObject_GC_Del(self); } static PyObject * @@ -512,16 +515,10 @@ memory_str(PyMemoryViewObject *self) } /* Sequence methods */ - static Py_ssize_t memory_length(PyMemoryViewObject *self) { - Py_buffer view; - - if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0) - return -1; - PyBuffer_Release(&view); - return view.len; + return get_shape0(&self->view); } /* @@ -589,40 +586,38 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) } } else if (PySlice_Check(key)) { - Py_ssize_t start, stop, step, slicelength; - + Py_ssize_t start, stop, step, slicelength; + if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } - if (step == 1 && view->ndim == 1) { - Py_buffer newview; - void *newbuf = (char *) view->buf - + start * view->itemsize; - int newflags = view->readonly - ? PyBUF_CONTIG_RO : PyBUF_CONTIG; + if (step == 1 && view->ndim == 1) { + Py_buffer newview; + void *newbuf = (char *) view->buf + + start * view->itemsize; + int newflags = view->readonly + ? PyBUF_CONTIG_RO : PyBUF_CONTIG; - /* XXX There should be an API to create a subbuffer */ - if (view->obj != NULL) { - if (PyObject_GetBuffer(view->obj, - &newview, newflags) == -1) - return NULL; - } - else { - newview = *view; - } - newview.buf = newbuf; - newview.len = slicelength; - newview.format = view->format; - if (view->shape == &(view->len)) - newview.shape = &(newview.len); - if (view->strides == &(view->itemsize)) - newview.strides = &(newview.itemsize); - return PyMemoryView_FromBuffer(&newview); - } - PyErr_SetNone(PyExc_NotImplementedError); - return NULL; + /* XXX There should be an API to create a subbuffer */ + if (view->obj != NULL) { + if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1) + return NULL; + } + else { + newview = *view; + } + newview.buf = newbuf; + newview.len = slicelength * newview.itemsize; + newview.format = view->format; + newview.shape = &(newview.smalltable[0]); + newview.shape[0] = slicelength; + newview.strides = &(newview.itemsize); + return PyMemoryView_FromBuffer(&newview); + } + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; } PyErr_Format(PyExc_TypeError, "cannot index memory using \"%.200s\"", @@ -747,7 +742,7 @@ memory_richcompare(PyObject *v, PyObject *w, int op) if (vv.itemsize != ww.itemsize || vv.len != ww.len) goto _end; - equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize); + equal = !memcmp(vv.buf, ww.buf, vv.len); _end: PyBuffer_Release(&vv); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 3a33429..8316e91 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1205,7 +1205,7 @@ PyObject *PyUnicode_Decode(const char *s, /* Decode via the codec registry */ buffer = NULL; - if (PyBuffer_FillInfo(&info, NULL, (void *)s, size, 1, PyBUF_SIMPLE) < 0) + if (PyBuffer_FillInfo(&info, NULL, (void *)s, size, 1, PyBUF_FULL_RO) < 0) goto onError; buffer = PyMemoryView_FromBuffer(&info); if (buffer == NULL) |