@@ -43,12 +43,24 @@ _getbytevalue(PyObject* arg, int *value)
4343 return 1 ;
4444}
4545
46+ static inline void
47+ bytearray_write_trailing_null_byte (PyByteArrayObject * self )
48+ {
49+ char * data = PyByteArray_AS_STRING (self );
50+ Py_ssize_t size = PyByteArray_GET_SIZE (self );
51+ data [size ] = '\0' ;
52+ }
53+
54+
4655static void
47- bytearray_reinit_from_bytes (PyByteArrayObject * self , Py_ssize_t size ,
48- Py_ssize_t alloc )
56+ bytearray_reinit_from_bytes (PyByteArrayObject * self , Py_ssize_t size )
4957{
58+ Py_ssize_t alloc = PyBytes_GET_SIZE (self -> ob_bytes_object );
59+ assert (0 <= size && size <= alloc );
60+
5061 /* Only the empty bytes may be immortal. */
5162 assert ((alloc == 0 ) == _Py_IsImmortal (self -> ob_bytes_object ));
63+
5264 self -> ob_bytes = self -> ob_start = PyBytes_AS_STRING (self -> ob_bytes_object );
5365 Py_SET_SIZE (self , size );
5466 FT_ATOMIC_STORE_SSIZE_RELAXED (self -> ob_alloc , alloc );
@@ -185,7 +197,7 @@ PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size)
185197 Py_DECREF (new );
186198 return NULL ;
187199 }
188- bytearray_reinit_from_bytes (new , size , size );
200+ bytearray_reinit_from_bytes (new , size );
189201 if (bytes != NULL && size > 0 ) {
190202 memcpy (new -> ob_bytes , bytes , size );
191203 }
@@ -211,6 +223,43 @@ PyByteArray_AsString(PyObject *self)
211223 return PyByteArray_AS_STRING (self );
212224}
213225
226+
227+ static int
228+ bytearray_resize_storage (PyByteArrayObject * self ,
229+ Py_ssize_t new_size , Py_ssize_t alloc )
230+ {
231+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (self );
232+ assert (1 <= new_size && new_size <= alloc );
233+
234+ Py_ssize_t size = Py_SIZE (self );
235+
236+ /* Re-align data to the start of the allocation. */
237+ char * old_start = self -> ob_start ;
238+ if (self -> ob_start != self -> ob_bytes ) {
239+ /* optimization tradeoff: This is faster than a new allocation when
240+ the number of bytes being removed in a resize is small; for
241+ large size changes it may be better to just make a new bytes
242+ object as _PyBytes_Resize will do a malloc + memcpy internally.
243+ */
244+ Py_ssize_t move = Py_MIN (new_size , size );
245+ memmove (self -> ob_bytes , self -> ob_start , move );
246+ self -> ob_start = self -> ob_bytes ;
247+ }
248+
249+ if (_PyBytes_ResizeKeepOnError (& self -> ob_bytes_object , alloc ) < 0 ) {
250+ if (old_start != self -> ob_bytes && new_size < size ) {
251+ // Move remaining bytes
252+ Py_ssize_t moved = new_size ;
253+ Py_ssize_t remaining = size - moved ;
254+ memmove (self -> ob_bytes + moved , old_start + moved , remaining );
255+ }
256+ bytearray_write_trailing_null_byte (self );
257+ return -1 ;
258+ }
259+ return 0 ;
260+ }
261+
262+
214263static int
215264bytearray_resize_lock_held (PyObject * self , Py_ssize_t requested_size )
216265{
@@ -246,7 +295,7 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
246295 if (requested_size == 0 ) {
247296 Py_SETREF (obj -> ob_bytes_object ,
248297 Py_GetConstant (Py_CONSTANT_EMPTY_BYTES ));
249- bytearray_reinit_from_bytes (obj , 0 , 0 );
298+ bytearray_reinit_from_bytes (obj , 0 );
250299 return 0 ;
251300 }
252301
@@ -261,7 +310,7 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
261310 /* Minor downsize; quick exit */
262311 Py_SET_SIZE (self , size );
263312 /* Add mid-buffer null; end provided by bytes. */
264- PyByteArray_AS_STRING ( self )[ size ] = '\0' ; /* Trailing null */
313+ bytearray_write_trailing_null_byte ( _PyByteArray_CAST ( self ));
265314 return 0 ;
266315 }
267316 }
@@ -281,28 +330,16 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size)
281330 return -1 ;
282331 }
283332
284- /* Re-align data to the start of the allocation. */
285- if (logical_offset > 0 ) {
286- /* optimization tradeoff: This is faster than a new allocation when
287- the number of bytes being removed in a resize is small; for large
288- size changes it may be better to just make a new bytes object as
289- _PyBytes_Resize will do a malloc + memcpy internally. */
290- memmove (obj -> ob_bytes , obj -> ob_start ,
291- Py_MIN (requested_size , Py_SIZE (self )));
333+ if (bytearray_resize_storage (obj , requested_size , (Py_ssize_t )alloc ) < 0 ) {
334+ return -1 ;
292335 }
293336
294- int ret = _PyBytes_Resize (& obj -> ob_bytes_object , alloc );
295- if (ret == -1 ) {
296- obj -> ob_bytes_object = Py_GetConstant (Py_CONSTANT_EMPTY_BYTES );
297- size = alloc = 0 ;
298- }
299- bytearray_reinit_from_bytes (obj , size , alloc );
337+ bytearray_reinit_from_bytes (obj , size );
300338 if (alloc != size ) {
301339 /* Add mid-buffer null; end provided by bytes. */
302- obj -> ob_bytes [ size ] = '\0' ;
340+ bytearray_write_trailing_null_byte ( obj ) ;
303341 }
304-
305- return ret ;
342+ return 0 ;
306343}
307344
308345int
@@ -928,7 +965,7 @@ bytearray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
928965 }
929966 PyByteArrayObject * self = _PyByteArray_CAST (op );
930967 self -> ob_bytes_object = Py_GetConstant (Py_CONSTANT_EMPTY_BYTES );
931- bytearray_reinit_from_bytes (self , 0 , 0 );
968+ bytearray_reinit_from_bytes (self , 0 );
932969 self -> ob_exports = 0 ;
933970 return op ;
934971}
@@ -995,9 +1032,9 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
9951032 && PyBytes_CheckExact (encoded )
9961033 && _PyBytes_GET_CACHED_HASH ((PyBytesObject * )encoded ) == -1 )
9971034 {
998- Py_ssize_t size = Py_SIZE (encoded );
1035+ Py_ssize_t size = PyBytes_GET_SIZE (encoded );
9991036 self -> ob_bytes_object = encoded ;
1000- bytearray_reinit_from_bytes (self , size , size );
1037+ bytearray_reinit_from_bytes (self , size );
10011038 return 0 ;
10021039 }
10031040 new = bytearray_iconcat ((PyObject * )self , encoded );
@@ -1121,7 +1158,7 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
11211158 /* Append the byte */
11221159 if (Py_SIZE (self ) + 1 < self -> ob_alloc ) {
11231160 Py_SET_SIZE (self , Py_SIZE (self ) + 1 );
1124- PyByteArray_AS_STRING (self )[ Py_SIZE ( self )] = '\0' ;
1161+ bytearray_write_trailing_null_byte (self );
11251162 }
11261163 else if (PyByteArray_Resize ((PyObject * )self , Py_SIZE (self )+ 1 ) < 0 )
11271164 goto error ;
@@ -1611,6 +1648,7 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16111648 }
16121649
16131650 Py_ssize_t remaining_length = size - to_take ;
1651+
16141652 // optimization: If taking less than leaving, just copy the small to_take
16151653 // portion out and move ob_start.
16161654 if (to_take < remaining_length ) {
@@ -1632,24 +1670,15 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16321670 memcpy (PyBytes_AS_STRING (remaining ), self -> ob_start + to_take ,
16331671 remaining_length );
16341672
1635- // If the bytes are offset inside the buffer must first align.
1636- if (self -> ob_start != self -> ob_bytes ) {
1637- memmove (self -> ob_bytes , self -> ob_start , to_take );
1638- self -> ob_start = self -> ob_bytes ;
1639- }
1640-
1641- if (_PyBytes_Resize (& self -> ob_bytes_object , to_take ) == -1 ) {
1642- assert (self -> ob_bytes_object == NULL );
1643- self -> ob_bytes_object = Py_GetConstant (Py_CONSTANT_EMPTY_BYTES );
1644- bytearray_reinit_from_bytes (self , 0 , 0 );
1673+ if (bytearray_resize_storage (self , to_take , to_take ) < 0 ) {
16451674 Py_DECREF (remaining );
16461675 return NULL ;
16471676 }
16481677
16491678 // Point the bytearray towards the buffer with the remaining data.
16501679 PyObject * result = self -> ob_bytes_object ;
16511680 self -> ob_bytes_object = remaining ;
1652- bytearray_reinit_from_bytes (self , remaining_length , remaining_length );
1681+ bytearray_reinit_from_bytes (self , remaining_length );
16531682 return result ;
16541683}
16551684
0 commit comments