Skip to content

Commit 0a33fd4

Browse files
committed
Fix bytearray_resize_storage()
Rename bytearray_realign_data_lock_held() to bytearray_resize_storage(). On error, only move data if ob_start was different than ob_bytes. Add one more test: resize() shrinks without logical offset.
1 parent 909270c commit 0a33fd4

2 files changed

Lines changed: 29 additions & 28 deletions

File tree

Lib/test/test_bytes.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,28 +1573,30 @@ def test_resize_error(self):
15731573
# gh-157242: If bytearray.resize() fails (memory allocation failure),
15741574
# the bytearray must be left unchanged.
15751575

1576-
# Simple bytearray
1577-
data = b'some data'
1578-
ba = bytearray(data)
1579-
with inject_memory_error(self, 0):
1580-
ba.resize(1024)
1581-
self.assertEqual(ba, bytearray(data))
1582-
1583-
# growing bytearray with non-zero logical start
1584-
ba = bytearray(b'0123456789')
1585-
expected = ba[3:]
1586-
del ba[:3]
1587-
with inject_memory_error(self, 0):
1588-
ba.resize(1024)
1589-
self.assertEqual(ba, expected)
1590-
1591-
# shrink bytearray with non-zero logical start
1592-
ba = bytearray(b'0123456789')
1593-
expected = ba[3:]
1594-
del ba[:3]
1595-
with inject_memory_error(self, 0):
1596-
ba.resize(1)
1597-
self.assertEqual(ba, expected)
1576+
offset = 3
1577+
for logical_offset in (False, True):
1578+
with self.subTest(logical_offset=logical_offset):
1579+
# grow bytearray
1580+
ba = bytearray(b'0123456789')
1581+
if logical_offset:
1582+
expected = ba[offset:]
1583+
del ba[:offset]
1584+
else:
1585+
expected = ba.copy()
1586+
with inject_memory_error(self, 0):
1587+
ba.resize(1024)
1588+
self.assertEqual(ba, expected)
1589+
1590+
# shrink bytearray
1591+
ba = bytearray(b'0123456789')
1592+
if logical_offset:
1593+
expected = ba[offset:]
1594+
del ba[:offset]
1595+
else:
1596+
expected = ba.copy()
1597+
with inject_memory_error(self, 0):
1598+
ba.resize(1)
1599+
self.assertEqual(ba, expected)
15981600

15991601
def test_take_bytes(self):
16001602
ba = bytearray(b'ab')

Objects/bytearrayobject.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ PyByteArray_AsString(PyObject *self)
225225

226226

227227
static int
228-
bytearray_realign_data_lock_held(PyByteArrayObject *self,
229-
Py_ssize_t new_size, Py_ssize_t alloc)
228+
bytearray_resize_storage(PyByteArrayObject *self,
229+
Py_ssize_t new_size, Py_ssize_t alloc)
230230
{
231231
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
232232
assert(1 <= new_size && new_size <= alloc);
@@ -247,7 +247,7 @@ bytearray_realign_data_lock_held(PyByteArrayObject *self,
247247
}
248248

249249
if (_PyBytes_ResizeKeepOnError(&self->ob_bytes_object, alloc) < 0) {
250-
if (new_size < size) {
250+
if (old_start != self->ob_bytes && new_size < size) {
251251
// Move remaining bytes
252252
Py_ssize_t moved = new_size;
253253
Py_ssize_t remaining = size - moved;
@@ -330,8 +330,7 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
330330
return -1;
331331
}
332332

333-
if (bytearray_realign_data_lock_held(obj, requested_size,
334-
(Py_ssize_t)alloc) < 0) {
333+
if (bytearray_resize_storage(obj, requested_size, (Py_ssize_t)alloc) < 0) {
335334
return -1;
336335
}
337336

@@ -1670,7 +1669,7 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16701669
memcpy(PyBytes_AS_STRING(remaining), self->ob_start + to_take,
16711670
remaining_length);
16721671

1673-
if (bytearray_realign_data_lock_held(self, to_take, to_take) < 0) {
1672+
if (bytearray_resize_storage(self, to_take, to_take) < 0) {
16741673
Py_DECREF(remaining);
16751674
return NULL;
16761675
}

0 commit comments

Comments
 (0)