Commit bc420400 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #4569: Interpreter crash when mutating a memoryview with an item size larger than 1.

(together with a bit of reindenting)
parent f9734076
...@@ -207,6 +207,15 @@ class MemoryviewTest(unittest.TestCase, CommonMemoryTests): ...@@ -207,6 +207,15 @@ class MemoryviewTest(unittest.TestCase, CommonMemoryTests):
self.assertRaises(TypeError, memoryview, argument=ob) self.assertRaises(TypeError, memoryview, argument=ob)
self.assertRaises(TypeError, memoryview, ob, argument=True) self.assertRaises(TypeError, memoryview, ob, argument=True)
def test_array_assign(self):
# Issue #4569: segfault when mutating a memoryview with itemsize != 1
from array import array
a = array('i', range(10))
m = memoryview(a)
new_a = array('i', range(9, -1, -1))
m[:] = new_a
self.assertEquals(a, new_a)
class MemorySliceTest(unittest.TestCase, CommonMemoryTests): class MemorySliceTest(unittest.TestCase, CommonMemoryTests):
base_object = b"XabcdefY" base_object = b"XabcdefY"
......
...@@ -29,6 +29,9 @@ Core and Builtins ...@@ -29,6 +29,9 @@ Core and Builtins
kept open but the file object behaves like a closed file. The ``FileIO`` kept open but the file object behaves like a closed file. The ``FileIO``
object also got a new readonly attribute ``closefd``. object also got a new readonly attribute ``closefd``.
- Issue #4569: Interpreter crash when mutating a memoryview with an item size
larger than 1.
Library Library
------- -------
......
...@@ -13,6 +13,18 @@ dup_buffer(Py_buffer *dest, Py_buffer *src) ...@@ -13,6 +13,18 @@ dup_buffer(Py_buffer *dest, Py_buffer *src)
dest->strides = &(dest->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;
}
static int static int
memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags) memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
{ {
...@@ -548,9 +560,9 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) ...@@ -548,9 +560,9 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key)
char *ptr; char *ptr;
ptr = (char *)view->buf; ptr = (char *)view->buf;
if (result < 0) { if (result < 0) {
result += view->shape[0]; result += get_shape0(view);
} }
if ((result < 0) || (result >= view->shape[0])) { if ((result < 0) || (result >= get_shape0(view))) {
PyErr_SetString(PyExc_IndexError, PyErr_SetString(PyExc_IndexError,
"index out of bounds"); "index out of bounds");
return NULL; return NULL;
...@@ -579,7 +591,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) ...@@ -579,7 +591,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key)
else if (PySlice_Check(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, view->len, if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
&start, &stop, &step, &slicelength) < 0) { &start, &stop, &step, &slicelength) < 0) {
return NULL; return NULL;
} }
...@@ -642,9 +654,9 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) ...@@ -642,9 +654,9 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
if (start == -1 && PyErr_Occurred()) if (start == -1 && PyErr_Occurred())
return -1; return -1;
if (start < 0) { if (start < 0) {
start += view->shape[0]; start += get_shape0(view);
} }
if ((start < 0) || (start >= view->shape[0])) { if ((start < 0) || (start >= get_shape0(view))) {
PyErr_SetString(PyExc_IndexError, PyErr_SetString(PyExc_IndexError,
"index out of bounds"); "index out of bounds");
return -1; return -1;
...@@ -654,7 +666,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) ...@@ -654,7 +666,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
else if (PySlice_Check(key)) { else if (PySlice_Check(key)) {
Py_ssize_t stop, step; Py_ssize_t stop, step;
if (PySlice_GetIndicesEx((PySliceObject*)key, view->len, if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
&start, &stop, &step, &len) < 0) { &start, &stop, &step, &len) < 0) {
return -1; return -1;
} }
...@@ -681,7 +693,8 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) ...@@ -681,7 +693,8 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name); view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
goto _error; goto _error;
} }
if (srcview.len != len) { bytelen = len * view->itemsize;
if (bytelen != srcview.len) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"cannot modify size of memoryview object"); "cannot modify size of memoryview object");
goto _error; goto _error;
...@@ -689,7 +702,6 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) ...@@ -689,7 +702,6 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
/* Do the actual copy */ /* Do the actual copy */
destbuf = (char *) view->buf + start * view->itemsize; destbuf = (char *) view->buf + start * view->itemsize;
srcbuf = (char *) srcview.buf; srcbuf = (char *) srcview.buf;
bytelen = len * view->itemsize;
if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf) if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
/* No overlapping */ /* No overlapping */
memcpy(destbuf, srcbuf, bytelen); memcpy(destbuf, srcbuf, bytelen);
......
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