Issue #4509: bugs in bytearray with exports (buffer protocol)
This commit is contained in:
parent
45313fe6e0
commit
ae5beceb35
|
@ -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):
|
||||
#
|
||||
|
|
|
@ -62,6 +62,9 @@ Core and Builtins
|
|||
KeyError would always report the empty frozenset([]) as the missing key. Now
|
||||
it correctly refers to the initial element.
|
||||
|
||||
- Issue #4509: Various issues surrounding resize of bytearray objects to
|
||||
which there are buffer exports.
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue