diff -r 3a42e5b47adb Lib/test/test_array.py --- a/Lib/test/test_array.py Sat Dec 13 04:03:41 2008 +0100 +++ b/Lib/test/test_array.py Tue Dec 16 22:26:36 2008 +0100 @@ -8,6 +8,7 @@ from test import support from weakref import proxy import array, io, math from pickle import loads, dumps +import operator class ArraySubclass(array.array): pass @@ -709,8 +710,23 @@ class BaseTest(unittest.TestCase): def test_buffer(self): a = array.array(self.typecode, self.example) - b = bytes(memoryview(a)) + m = memoryview(a) + b = bytes(m) + self.assertEqual(b, a.tostring()) self.assertEqual(b[0], a.tostring()[0]) + # Resizing is forbidden when there are buffer exports + self.assertRaises(BufferError, a.append, a[0]) + self.assertRaises(BufferError, a.extend, a[0:1]) + self.assertRaises(BufferError, a.remove, a[0]) + self.assertRaises(BufferError, a.fromlist, a.tolist()) + self.assertRaises(BufferError, a.fromstring, a.tostring()) + if self.typecode == 'u': + self.assertRaises(BufferError, a.fromunicode, a.tounicode()) + self.assertRaises(BufferError, operator.setitem, a, slice(0, 0), a) + self.assertRaises(BufferError, operator.delitem, a, 0) + self.assertRaises(BufferError, operator.delitem, a, slice(0, 1)) + self.assertRaises(BufferError, operator.irepeat, a, 2) + self.assertRaises(BufferError, operator.irepeat, a, 0) def test_weakref(self): s = array.array(self.typecode, self.example) diff -r 3a42e5b47adb Modules/arraymodule.c --- a/Modules/arraymodule.c Sat Dec 13 04:03:41 2008 +0100 +++ b/Modules/arraymodule.c Tue Dec 16 22:26:36 2008 +0100 @@ -49,9 +49,15 @@ array_resize(arrayobject *self, Py_ssize char *items; size_t _new_size; + if (self->ob_exports > 0 && newsize != Py_SIZE(self)) { + PyErr_SetString(PyExc_BufferError, + "cannot resize an array that is exporting buffers"); + return -1; + } + /* Bypass realloc() when a previous overallocation is large enough to accommodate the newsize. If the newsize is 16 smaller than the - current size, then proceed with the realloc() to shrink the list. + current size, then proceed with the realloc() to shrink the array. */ if (self->allocated >= newsize && @@ -61,11 +67,13 @@ array_resize(arrayobject *self, Py_ssize return 0; } - if (self->ob_exports > 0) { - PyErr_SetString(PyExc_BufferError, - "cannot resize an array that is exporting data"); - return -1; - } + if (newsize == 0) { + PyMem_FREE(self->ob_item); + self->ob_item = NULL; + Py_SIZE(self) = 0; + self->allocated = 0; + return 0; + } /* This over-allocates proportional to the array size, making room * for additional growth. The over-allocation is mild, but is @@ -731,25 +739,15 @@ array_ass_slice(arrayobject *a, Py_ssize memmove(item + (ihigh+d)*a->ob_descr->itemsize, item + ihigh*a->ob_descr->itemsize, (Py_SIZE(a)-ihigh)*a->ob_descr->itemsize); - Py_SIZE(a) += d; - PyMem_RESIZE(item, char, Py_SIZE(a)*a->ob_descr->itemsize); - /* Can't fail */ - a->ob_item = item; - a->allocated = Py_SIZE(a); + if (array_resize(a, Py_SIZE(a) + d) == -1) + return -1; } else if (d > 0) { /* Insert d items */ - PyMem_RESIZE(item, char, - (Py_SIZE(a) + d)*a->ob_descr->itemsize); - if (item == NULL) { - PyErr_NoMemory(); + if (array_resize(a, Py_SIZE(a) + d)) return -1; - } memmove(item + (ihigh+d)*a->ob_descr->itemsize, item + ihigh*a->ob_descr->itemsize, (Py_SIZE(a)-ihigh)*a->ob_descr->itemsize); - a->ob_item = item; - Py_SIZE(a) += d; - a->allocated = Py_SIZE(a); } if (n > 0) memcpy(item + ilow*a->ob_descr->itemsize, b->ob_item, @@ -804,8 +802,7 @@ array_iter_extend(arrayobject *self, PyO static int array_do_extend(arrayobject *self, PyObject *bb) { - Py_ssize_t size; - char *old_item; + Py_ssize_t size, oldsize; if (!array_Check(bb)) return array_iter_extend(self, bb); @@ -820,18 +817,12 @@ array_do_extend(arrayobject *self, PyObj PyErr_NoMemory(); return -1; } - size = Py_SIZE(self) + Py_SIZE(b); - old_item = self->ob_item; - PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize); - if (self->ob_item == NULL) { - self->ob_item = old_item; - PyErr_NoMemory(); + oldsize = Py_SIZE(self); + size = oldsize + Py_SIZE(b); + if (array_resize(self, size) == -1) return -1; - } - memcpy(self->ob_item + Py_SIZE(self)*self->ob_descr->itemsize, - b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize); - Py_SIZE(self) = size; - self->allocated = size; + memcpy(self->ob_item + oldsize * self->ob_descr->itemsize, + b->ob_item, Py_SIZE(b) * b->ob_descr->itemsize); return 0; #undef b @@ -867,27 +858,15 @@ array_inplace_repeat(arrayobject *self, return PyErr_NoMemory(); } size = Py_SIZE(self) * self->ob_descr->itemsize; - if (n == 0) { - PyMem_FREE(items); - self->ob_item = NULL; - Py_SIZE(self) = 0; - self->allocated = 0; + if (n > 0 && size > PY_SSIZE_T_MAX / n) { + return PyErr_NoMemory(); } - else { - if (size > PY_SSIZE_T_MAX / n) { - return PyErr_NoMemory(); - } - PyMem_RESIZE(items, char, n * size); - if (items == NULL) - return PyErr_NoMemory(); - p = items; - for (i = 1; i < n; i++) { - p += size; - memcpy(p, items, size); - } - self->ob_item = items; - Py_SIZE(self) *= n; - self->allocated = Py_SIZE(self); + if (array_resize(self, n * Py_SIZE(self)) == -1) + return NULL; + items = p = self->ob_item; + for (i = 1; i < n; i++) { + p += size; + memcpy(p, items, size); } } Py_INCREF(self); @@ -1312,7 +1291,6 @@ static PyObject * array_fromlist(arrayobject *self, PyObject *list) { Py_ssize_t n; - Py_ssize_t itemsize = self->ob_descr->itemsize; if (!PyList_Check(list)) { PyErr_SetString(PyExc_TypeError, "arg must be list"); @@ -1320,28 +1298,15 @@ array_fromlist(arrayobject *self, PyObje } n = PyList_Size(list); if (n > 0) { - char *item = self->ob_item; - Py_ssize_t i; - PyMem_RESIZE(item, char, (Py_SIZE(self) + n) * itemsize); - if (item == NULL) { - PyErr_NoMemory(); + Py_ssize_t i, old_size; + old_size = Py_SIZE(self); + if (array_resize(self, old_size + n) == -1) return NULL; - } - self->ob_item = item; - Py_SIZE(self) += n; - self->allocated = Py_SIZE(self); for (i = 0; i < n; i++) { PyObject *v = PyList_GetItem(list, i); if ((*self->ob_descr->setitem)(self, Py_SIZE(self) - n + i, v) != 0) { - Py_SIZE(self) -= n; - if (itemsize && (Py_SIZE(self) > PY_SSIZE_T_MAX / itemsize)) { - return PyErr_NoMemory(); - } - PyMem_RESIZE(item, char, - Py_SIZE(self) * itemsize); - self->ob_item = item; - self->allocated = Py_SIZE(self); + array_resize(self, old_size); return NULL; } } @@ -1395,21 +1360,15 @@ array_fromstring(arrayobject *self, PyOb } n = n / itemsize; if (n > 0) { - char *item = self->ob_item; - if ((n > PY_SSIZE_T_MAX - Py_SIZE(self)) || - ((Py_SIZE(self) + n) > PY_SSIZE_T_MAX / itemsize)) { + Py_ssize_t old_size = Py_SIZE(self); + if ((n > PY_SSIZE_T_MAX - old_size) || + ((old_size + n) > PY_SSIZE_T_MAX / itemsize)) { return PyErr_NoMemory(); } - PyMem_RESIZE(item, char, (Py_SIZE(self) + n) * itemsize); - if (item == NULL) { - PyErr_NoMemory(); + if (array_resize(self, old_size + n) == -1) return NULL; - } - self->ob_item = item; - Py_SIZE(self) += n; - self->allocated = Py_SIZE(self); - memcpy(item + (Py_SIZE(self) - n) * itemsize, - str, itemsize*n); + memcpy(self->ob_item + old_size * itemsize, + str, n * itemsize); } Py_INCREF(Py_None); return Py_None; @@ -1458,19 +1417,10 @@ array_fromunicode(arrayobject *self, PyO return NULL; } if (n > 0) { - Py_UNICODE *item = (Py_UNICODE *) self->ob_item; - if (Py_SIZE(self) > PY_SSIZE_T_MAX - n) { - return PyErr_NoMemory(); - } - PyMem_RESIZE(item, Py_UNICODE, Py_SIZE(self) + n); - if (item == NULL) { - PyErr_NoMemory(); + Py_ssize_t old_size = Py_SIZE(self); + if (array_resize(self, old_size + n) == -1) return NULL; - } - self->ob_item = (char *) item; - Py_SIZE(self) += n; - self->allocated = Py_SIZE(self); - memcpy(item + Py_SIZE(self) - n, + memcpy(self->ob_item + old_size * sizeof(Py_UNICODE), ustr, n * sizeof(Py_UNICODE)); } @@ -1740,12 +1690,12 @@ array_ass_subscr(arrayobject* self, PyOb self->ob_item + stop * itemsize, (Py_SIZE(self) - stop) * itemsize); if (array_resize(self, Py_SIZE(self) + - needed - slicelength) < 0) + needed - slicelength) < 0) return -1; } else if (slicelength < needed) { if (array_resize(self, Py_SIZE(self) + - needed - slicelength) < 0) + needed - slicelength) < 0) return -1; memmove(self->ob_item + (start + needed) * itemsize, self->ob_item + stop * itemsize,