Merged revisions 67619 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  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)
........
This commit is contained in:
Antoine Pitrou 2008-12-07 00:07:51 +00:00
parent b7387a5e0d
commit 599db7f133
3 changed files with 66 additions and 11 deletions

View File

@ -752,6 +752,38 @@ class ByteArrayTest(BaseBytesTest):
self.assertEqual(b, b"") self.assertEqual(b, b"")
self.assertEqual(c, 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): class AssortedBytesTest(unittest.TestCase):
# #

View File

@ -20,6 +20,9 @@ Core and Builtins
- Issue #3689: The list reversed iterator now supports __length_hint__ - Issue #3689: The list reversed iterator now supports __length_hint__
instead of __len__. Behavior now matches other reversed iterators. 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 Library
------- -------

View File

@ -154,6 +154,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 *
@ -229,6 +240,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;
@ -248,16 +266,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();
@ -522,6 +530,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------>|
@ -654,6 +666,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
@ -689,6 +703,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;
@ -1473,7 +1489,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]);
@ -2730,6 +2746,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);
@ -2760,6 +2778,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)