From 599db7f133ee842e94c89ceaa1724a0a84dded11 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 7 Dec 2008 00:07:51 +0000 Subject: [PATCH] Merged revisions 67619 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ........ r67619 | antoine.pitrou | 2008-12-06 22:29:24 +0100 (sam., 06 déc. 2008) | 1 line Issue #4509: bugs in bytearray with exports (buffer protocol) ........ --- Lib/test/test_bytes.py | 32 +++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 42 +++++++++++++++++++++++++++++---------- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 45df1f34b5f..36defb8a846 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -752,6 +752,38 @@ class ByteArrayTest(BaseBytesTest): self.assertEqual(b, b"") self.assertEqual(c, b"") + # XXX memoryview not available + def XXXtest_resize_forbidden(self): + # #4509: can't resize a bytearray when there are buffer exports, even + # if it wouldn't reallocate the underlying buffer. + # Furthermore, no destructive changes to the buffer may be applied + # before raising the error. + b = bytearray(range(10)) + v = memoryview(b) + def resize(n): + b[1:-1] = range(n + 1, 2*n - 1) + resize(10) + orig = b[:] + self.assertRaises(BufferError, resize, 11) + self.assertEquals(b, orig) + self.assertRaises(BufferError, resize, 9) + self.assertEquals(b, orig) + self.assertRaises(BufferError, resize, 0) + self.assertEquals(b, orig) + # Other operations implying resize + self.assertRaises(BufferError, b.pop, 0) + self.assertEquals(b, orig) + self.assertRaises(BufferError, b.remove, b[1]) + self.assertEquals(b, orig) + def delitem(): + del b[1] + self.assertRaises(BufferError, delitem) + self.assertEquals(b, orig) + # deleting a non-contiguous slice + def delslice(): + b[1:-1:2] = b"" + self.assertRaises(BufferError, delslice) + self.assertEquals(b, orig) class AssortedBytesTest(unittest.TestCase): # diff --git a/Misc/NEWS b/Misc/NEWS index 0fac2aafba7..67111796842 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,9 @@ Core and Builtins - Issue #3689: The list reversed iterator now supports __length_hint__ instead of __len__. Behavior now matches other reversed iterators. +- Issue #4509: Various issues surrounding resize of bytearray objects to + which there are buffer exports. + Library ------- diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 99bb0f204f2..d75eb53e437 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -154,6 +154,17 @@ _getbuffer(PyObject *obj, Py_buffer *view) return view->len; } +static int +_canresize(PyByteArrayObject *self) +{ + if (self->ob_exports > 0) { + PyErr_SetString(PyExc_BufferError, + "Existing exports of data: object cannot be re-sized"); + return 0; + } + return 1; +} + /* Direct API functions */ PyObject * @@ -229,6 +240,13 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) assert(PyByteArray_Check(self)); assert(size >= 0); + if (size == Py_SIZE(self)) { + return 0; + } + if (!_canresize((PyByteArrayObject *)self)) { + return -1; + } + if (size < alloc / 2) { /* Major downsize; resize down to exact size */ alloc = size + 1; @@ -248,16 +266,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) alloc = size + 1; } - if (((PyByteArrayObject *)self)->ob_exports > 0) { - /* - fprintf(stderr, "%d: %s", ((PyByteArrayObject *)self)->ob_exports, - ((PyByteArrayObject *)self)->ob_bytes); - */ - PyErr_SetString(PyExc_BufferError, - "Existing exports of data: object cannot be re-sized"); - return -1; - } - sval = PyMem_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc); if (sval == NULL) { PyErr_NoMemory(); @@ -522,6 +530,10 @@ bytes_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, if (avail != needed) { if (avail > needed) { + if (!_canresize(self)) { + res = -1; + goto finish; + } /* 0 lo hi old_size | |<----avail----->|<-----tomove------>| @@ -654,6 +666,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) stop = start; if (step == 1) { if (slicelen != needed) { + if (!_canresize(self)) + return -1; if (slicelen > needed) { /* 0 start stop old_size @@ -689,6 +703,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) /* Delete slice */ Py_ssize_t cur, i; + if (!_canresize(self)) + return -1; if (step < 0) { stop = start + 1; start = stop + step * (slicelen - 1) - 1; @@ -1473,7 +1489,7 @@ bytes_translate(PyByteArrayObject *self, PyObject *args) } goto done; } - + for (i = 0; i < 256; i++) trans_table[i] = Py_CHARMASK(table[i]); @@ -2730,6 +2746,8 @@ bytes_pop(PyByteArrayObject *self, PyObject *args) PyErr_SetString(PyExc_IndexError, "pop index out of range"); return NULL; } + if (!_canresize(self)) + return NULL; value = self->ob_bytes[where]; memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); @@ -2760,6 +2778,8 @@ bytes_remove(PyByteArrayObject *self, PyObject *arg) PyErr_SetString(PyExc_ValueError, "value not found in bytes"); return NULL; } + if (!_canresize(self)) + return NULL; memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); if (PyByteArray_Resize((PyObject *)self, n - 1) < 0)