@@ -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}
@@ -994,9 +1031,9 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
9941031 if (_PyObject_IsUniquelyReferenced (encoded )
9951032 && PyBytes_CheckExact (encoded ))
9961033 {
997- Py_ssize_t size = Py_SIZE (encoded );
1034+ Py_ssize_t size = PyBytes_GET_SIZE (encoded );
9981035 self -> ob_bytes_object = encoded ;
999- bytearray_reinit_from_bytes (self , size , size );
1036+ bytearray_reinit_from_bytes (self , size );
10001037 return 0 ;
10011038 }
10021039 new = bytearray_iconcat ((PyObject * )self , encoded );
@@ -1120,7 +1157,7 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
11201157 /* Append the byte */
11211158 if (Py_SIZE (self ) + 1 < self -> ob_alloc ) {
11221159 Py_SET_SIZE (self , Py_SIZE (self ) + 1 );
1123- PyByteArray_AS_STRING (self )[ Py_SIZE ( self )] = '\0' ;
1160+ bytearray_write_trailing_null_byte (self );
11241161 }
11251162 else if (PyByteArray_Resize ((PyObject * )self , Py_SIZE (self )+ 1 ) < 0 )
11261163 goto error ;
@@ -1610,6 +1647,7 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16101647 }
16111648
16121649 Py_ssize_t remaining_length = size - to_take ;
1650+
16131651 // optimization: If taking less than leaving, just copy the small to_take
16141652 // portion out and move ob_start.
16151653 if (to_take < remaining_length ) {
@@ -1631,24 +1669,15 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16311669 memcpy (PyBytes_AS_STRING (remaining ), self -> ob_start + to_take ,
16321670 remaining_length );
16331671
1634- // If the bytes are offset inside the buffer must first align.
1635- if (self -> ob_start != self -> ob_bytes ) {
1636- memmove (self -> ob_bytes , self -> ob_start , to_take );
1637- self -> ob_start = self -> ob_bytes ;
1638- }
1639-
1640- if (_PyBytes_Resize (& self -> ob_bytes_object , to_take ) == -1 ) {
1641- assert (self -> ob_bytes_object == NULL );
1642- self -> ob_bytes_object = Py_GetConstant (Py_CONSTANT_EMPTY_BYTES );
1643- bytearray_reinit_from_bytes (self , 0 , 0 );
1672+ if (bytearray_resize_storage (self , to_take , to_take ) < 0 ) {
16441673 Py_DECREF (remaining );
16451674 return NULL ;
16461675 }
16471676
16481677 // Point the bytearray towards the buffer with the remaining data.
16491678 PyObject * result = self -> ob_bytes_object ;
16501679 self -> ob_bytes_object = remaining ;
1651- bytearray_reinit_from_bytes (self , remaining_length , remaining_length );
1680+ bytearray_reinit_from_bytes (self , remaining_length );
16521681 return result ;
16531682}
16541683
0 commit comments