Skip to content

Commit e9e1f02

Browse files
committed
Add bytearray_realign_data_lock_held()
1 parent ba1e2c8 commit e9e1f02

1 file changed

Lines changed: 47 additions & 49 deletions

File tree

Objects/bytearrayobject.c

Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,47 @@ PyByteArray_AsString(PyObject *self)
214214
return PyByteArray_AS_STRING(self);
215215
}
216216

217+
218+
static int
219+
bytearray_realign_data_lock_held(PyByteArrayObject *self, Py_ssize_t new_size, Py_ssize_t alloc)
220+
{
221+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
222+
assert(1 <= new_size && new_size <= alloc);
223+
224+
Py_ssize_t size = Py_SIZE(self);
225+
size_t logical_offset = (size_t) (self->ob_start - self->ob_bytes);
226+
227+
if (logical_offset == 0 || new_size >= size) {
228+
/* Re-align data to the start of the allocation. */
229+
if (logical_offset != 0) {
230+
/* optimization tradeoff: This is faster than a new allocation when
231+
the number of bytes being removed in a resize is small; for
232+
large size changes it may be better to just make a new bytes
233+
object as _PyBytes_Resize will do a malloc + memcpy internally.
234+
*/
235+
memmove(self->ob_bytes, self->ob_start, size);
236+
self->ob_start = self->ob_bytes;
237+
}
238+
239+
if (_PyBytes_ResizeKeepOnError(&self->ob_bytes_object, alloc) < 0) {
240+
return -1;
241+
}
242+
}
243+
else {
244+
// Using memmove() would be unsafe, since _PyBytes_ResizeKeepOnError()
245+
// failure code path would be unable to restore the bytearray to its
246+
// previous state.
247+
PyObject *resized = PyBytes_FromStringAndSize(NULL, alloc);
248+
if (resized == NULL) {
249+
return -1;
250+
}
251+
memcpy(PyBytes_AS_STRING(resized), self->ob_start, new_size);
252+
Py_SETREF(self->ob_bytes_object, resized);
253+
}
254+
return 0;
255+
}
256+
257+
217258
static int
218259
bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
219260
{
@@ -284,31 +325,9 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
284325
return -1;
285326
}
286327

287-
if (logical_offset == 0 || requested_size >= Py_SIZE(self)) {
288-
/* Re-align data to the start of the allocation. */
289-
if (logical_offset > 0) {
290-
/* optimization tradeoff: This is faster than a new allocation when
291-
the number of bytes being removed in a resize is small; for large
292-
size changes it may be better to just make a new bytes object as
293-
_PyBytes_Resize will do a malloc + memcpy internally. */
294-
memmove(obj->ob_bytes, obj->ob_start, Py_SIZE(self));
295-
obj->ob_start = obj->ob_bytes;
296-
}
297-
298-
if (_PyBytes_ResizeKeepOnError(&obj->ob_bytes_object, alloc) < 0) {
299-
return -1;
300-
}
301-
}
302-
else {
303-
// Using memmove() would be unsafe, since _PyBytes_ResizeKeepOnError()
304-
// failure code path would be unable to restore the bytearray to its
305-
// previous state.
306-
PyObject *resized = PyBytes_FromStringAndSize(NULL, alloc);
307-
if (resized == NULL) {
308-
return -1;
309-
}
310-
memcpy(PyBytes_AS_STRING(resized), obj->ob_start, requested_size);
311-
Py_SETREF(obj->ob_bytes_object, resized);
328+
if (bytearray_realign_data_lock_held(obj, requested_size,
329+
(Py_ssize_t)alloc) < 0) {
330+
return -1;
312331
}
313332

314333
bytearray_reinit_from_bytes(obj, size);
@@ -1646,30 +1665,9 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16461665
memcpy(PyBytes_AS_STRING(remaining), self->ob_start + to_take,
16471666
remaining_length);
16481667

1649-
size_t logical_offset = (size_t) (self->ob_start - self->ob_bytes);
1650-
if (logical_offset == 0 || remaining_length == 0) {
1651-
// If the bytes are offset inside the buffer must first align.
1652-
if (logical_offset != 0) {
1653-
memmove(self->ob_bytes, self->ob_start, to_take);
1654-
self->ob_start = self->ob_bytes;
1655-
}
1656-
1657-
if (_PyBytes_ResizeKeepOnError(&self->ob_bytes_object, to_take) == -1) {
1658-
Py_DECREF(remaining);
1659-
return NULL;
1660-
}
1661-
}
1662-
else {
1663-
// Using memmove() would be unsafe, since _PyBytes_ResizeKeepOnError()
1664-
// failure code path would be unable to restore the bytearray to its
1665-
// previous state.
1666-
PyObject *resized = PyBytes_FromStringAndSize(NULL, to_take);
1667-
if (resized == NULL) {
1668-
Py_DECREF(remaining);
1669-
return NULL;
1670-
}
1671-
memcpy(PyBytes_AS_STRING(resized), self->ob_start, to_take);
1672-
Py_SETREF(self->ob_bytes_object, resized);
1668+
if (bytearray_realign_data_lock_held(self, to_take, to_take) < 0) {
1669+
Py_DECREF(remaining);
1670+
return NULL;
16731671
}
16741672

16751673
// Point the bytearray towards the buffer with the remaining data.

0 commit comments

Comments
 (0)