Commit 5504e893 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #4509: bugs in bytearray with exports (buffer protocol)

parent e6d4a9bd
...@@ -769,6 +769,37 @@ class ByteArrayTest(BaseBytesTest): ...@@ -769,6 +769,37 @@ class ByteArrayTest(BaseBytesTest):
self.assertEqual(b, b"") self.assertEqual(b, b"")
self.assertEqual(c, b"") self.assertEqual(c, b"")
def test_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): class AssortedBytesTest(unittest.TestCase):
# #
......
...@@ -21,6 +21,9 @@ Core and Builtins ...@@ -21,6 +21,9 @@ Core and Builtins
growing read buffer. Fixed by using the same growth rate algorithm as growing read buffer. Fixed by using the same growth rate algorithm as
Python 2.x. Python 2.x.
- Issue #4509: Various issues surrounding resize of bytearray objects to
which there are buffer exports (e.g. memoryview instances).
Library Library
------- -------
......
...@@ -100,6 +100,17 @@ _getbuffer(PyObject *obj, Py_buffer *view) ...@@ -100,6 +100,17 @@ _getbuffer(PyObject *obj, Py_buffer *view)
return view->len; 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 */ /* Direct API functions */
PyObject * PyObject *
...@@ -180,6 +191,13 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) ...@@ -180,6 +191,13 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
assert(PyByteArray_Check(self)); assert(PyByteArray_Check(self));
assert(size >= 0); assert(size >= 0);
if (size == Py_SIZE(self)) {
return 0;
}
if (!_canresize((PyByteArrayObject *)self)) {
return -1;
}
if (size < alloc / 2) { if (size < alloc / 2) {
/* Major downsize; resize down to exact size */ /* Major downsize; resize down to exact size */
alloc = size + 1; alloc = size + 1;
...@@ -199,16 +217,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) ...@@ -199,16 +217,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
alloc = size + 1; 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); sval = PyMem_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc);
if (sval == NULL) { if (sval == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
...@@ -473,6 +481,10 @@ bytes_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, ...@@ -473,6 +481,10 @@ bytes_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi,
if (avail != needed) { if (avail != needed) {
if (avail > needed) { if (avail > needed) {
if (!_canresize(self)) {
res = -1;
goto finish;
}
/* /*
0 lo hi old_size 0 lo hi old_size
| |<----avail----->|<-----tomove------>| | |<----avail----->|<-----tomove------>|
...@@ -605,6 +617,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) ...@@ -605,6 +617,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
stop = start; stop = start;
if (step == 1) { if (step == 1) {
if (slicelen != needed) { if (slicelen != needed) {
if (!_canresize(self))
return -1;
if (slicelen > needed) { if (slicelen > needed) {
/* /*
0 start stop old_size 0 start stop old_size
...@@ -640,6 +654,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) ...@@ -640,6 +654,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
/* Delete slice */ /* Delete slice */
Py_ssize_t cur, i; Py_ssize_t cur, i;
if (!_canresize(self))
return -1;
if (step < 0) { if (step < 0) {
stop = start + 1; stop = start + 1;
start = stop + step * (slicelen - 1) - 1; start = stop + step * (slicelen - 1) - 1;
...@@ -1401,7 +1417,7 @@ bytes_translate(PyByteArrayObject *self, PyObject *args) ...@@ -1401,7 +1417,7 @@ bytes_translate(PyByteArrayObject *self, PyObject *args)
} }
goto done; goto done;
} }
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
trans_table[i] = Py_CHARMASK(table[i]); trans_table[i] = Py_CHARMASK(table[i]);
...@@ -2659,6 +2675,8 @@ bytes_pop(PyByteArrayObject *self, PyObject *args) ...@@ -2659,6 +2675,8 @@ bytes_pop(PyByteArrayObject *self, PyObject *args)
PyErr_SetString(PyExc_IndexError, "pop index out of range"); PyErr_SetString(PyExc_IndexError, "pop index out of range");
return NULL; return NULL;
} }
if (!_canresize(self))
return NULL;
value = self->ob_bytes[where]; value = self->ob_bytes[where];
memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
...@@ -2689,6 +2707,8 @@ bytes_remove(PyByteArrayObject *self, PyObject *arg) ...@@ -2689,6 +2707,8 @@ bytes_remove(PyByteArrayObject *self, PyObject *arg)
PyErr_SetString(PyExc_ValueError, "value not found in bytes"); PyErr_SetString(PyExc_ValueError, "value not found in bytes");
return NULL; return NULL;
} }
if (!_canresize(self))
return NULL;
memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where); memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
if (PyByteArray_Resize((PyObject *)self, n - 1) < 0) if (PyByteArray_Resize((PyObject *)self, n - 1) < 0)
......
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