Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5504e89

Browse files
committed
Issue #4509: bugs in bytearray with exports (buffer protocol)
1 parent e6d4a9b commit 5504e89

3 files changed

Lines changed: 65 additions & 11 deletions

File tree

Lib/test/test_bytes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,37 @@ def test_partition_bytearray_doesnt_share_nullstring(self):
769769
self.assertEqual(b, b"")
770770
self.assertEqual(c, b"")
771771

772+
def test_resize_forbidden(self):
773+
# #4509: can't resize a bytearray when there are buffer exports, even
774+
# if it wouldn't reallocate the underlying buffer.
775+
# Furthermore, no destructive changes to the buffer may be applied
776+
# before raising the error.
777+
b = bytearray(range(10))
778+
v = memoryview(b)
779+
def resize(n):
780+
b[1:-1] = range(n + 1, 2*n - 1)
781+
resize(10)
782+
orig = b[:]
783+
self.assertRaises(BufferError, resize, 11)
784+
self.assertEquals(b, orig)
785+
self.assertRaises(BufferError, resize, 9)
786+
self.assertEquals(b, orig)
787+
self.assertRaises(BufferError, resize, 0)
788+
self.assertEquals(b, orig)
789+
# Other operations implying resize
790+
self.assertRaises(BufferError, b.pop, 0)
791+
self.assertEquals(b, orig)
792+
self.assertRaises(BufferError, b.remove, b[1])
793+
self.assertEquals(b, orig)
794+
def delitem():
795+
del b[1]
796+
self.assertRaises(BufferError, delitem)
797+
self.assertEquals(b, orig)
798+
# deleting a non-contiguous slice
799+
def delslice():
800+
b[1:-1:2] = b""
801+
self.assertRaises(BufferError, delslice)
802+
self.assertEquals(b, orig)
772803

773804
class AssortedBytesTest(unittest.TestCase):
774805
#

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Core and Builtins
2121
growing read buffer. Fixed by using the same growth rate algorithm as
2222
Python 2.x.
2323

24+
- Issue #4509: Various issues surrounding resize of bytearray objects to
25+
which there are buffer exports (e.g. memoryview instances).
26+
2427

2528
Library
2629
-------

Objects/bytearrayobject.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ _getbuffer(PyObject *obj, Py_buffer *view)
100100
return view->len;
101101
}
102102

103+
static int
104+
_canresize(PyByteArrayObject *self)
105+
{
106+
if (self->ob_exports > 0) {
107+
PyErr_SetString(PyExc_BufferError,
108+
"Existing exports of data: object cannot be re-sized");
109+
return 0;
110+
}
111+
return 1;
112+
}
113+
103114
/* Direct API functions */
104115

105116
PyObject *
@@ -180,6 +191,13 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
180191
assert(PyByteArray_Check(self));
181192
assert(size >= 0);
182193

194+
if (size == Py_SIZE(self)) {
195+
return 0;
196+
}
197+
if (!_canresize((PyByteArrayObject *)self)) {
198+
return -1;
199+
}
200+
183201
if (size < alloc / 2) {
184202
/* Major downsize; resize down to exact size */
185203
alloc = size + 1;
@@ -199,16 +217,6 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size)
199217
alloc = size + 1;
200218
}
201219

202-
if (((PyByteArrayObject *)self)->ob_exports > 0) {
203-
/*
204-
fprintf(stderr, "%d: %s", ((PyByteArrayObject *)self)->ob_exports,
205-
((PyByteArrayObject *)self)->ob_bytes);
206-
*/
207-
PyErr_SetString(PyExc_BufferError,
208-
"Existing exports of data: object cannot be re-sized");
209-
return -1;
210-
}
211-
212220
sval = PyMem_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc);
213221
if (sval == NULL) {
214222
PyErr_NoMemory();
@@ -473,6 +481,10 @@ bytes_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi,
473481

474482
if (avail != needed) {
475483
if (avail > needed) {
484+
if (!_canresize(self)) {
485+
res = -1;
486+
goto finish;
487+
}
476488
/*
477489
0 lo hi old_size
478490
| |<----avail----->|<-----tomove------>|
@@ -605,6 +617,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
605617
stop = start;
606618
if (step == 1) {
607619
if (slicelen != needed) {
620+
if (!_canresize(self))
621+
return -1;
608622
if (slicelen > needed) {
609623
/*
610624
0 start stop old_size
@@ -640,6 +654,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
640654
/* Delete slice */
641655
Py_ssize_t cur, i;
642656

657+
if (!_canresize(self))
658+
return -1;
643659
if (step < 0) {
644660
stop = start + 1;
645661
start = stop + step * (slicelen - 1) - 1;
@@ -1401,7 +1417,7 @@ bytes_translate(PyByteArrayObject *self, PyObject *args)
14011417
}
14021418
goto done;
14031419
}
1404-
1420+
14051421
for (i = 0; i < 256; i++)
14061422
trans_table[i] = Py_CHARMASK(table[i]);
14071423

@@ -2659,6 +2675,8 @@ bytes_pop(PyByteArrayObject *self, PyObject *args)
26592675
PyErr_SetString(PyExc_IndexError, "pop index out of range");
26602676
return NULL;
26612677
}
2678+
if (!_canresize(self))
2679+
return NULL;
26622680

26632681
value = self->ob_bytes[where];
26642682
memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
@@ -2689,6 +2707,8 @@ bytes_remove(PyByteArrayObject *self, PyObject *arg)
26892707
PyErr_SetString(PyExc_ValueError, "value not found in bytes");
26902708
return NULL;
26912709
}
2710+
if (!_canresize(self))
2711+
return NULL;
26922712

26932713
memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
26942714
if (PyByteArray_Resize((PyObject *)self, n - 1) < 0)

0 commit comments

Comments
 (0)