@@ -453,54 +453,80 @@ bytearray_setslice_linear(PyByteArrayObject *self,
453453 Py_ssize_t avail = hi - lo ;
454454 char * buf = PyByteArray_AS_STRING (self );
455455 Py_ssize_t growth = bytes_len - avail ;
456+ int res = 0 ;
456457 assert (avail >= 0 );
457458
458- if (growth != 0 ) {
459- if (growth < 0 ) {
460- if (!_canresize (self ))
461- return -1 ;
459+ if (growth < 0 ) {
460+ if (!_canresize (self ))
461+ return -1 ;
462+
463+ if (lo == 0 ) {
464+ /* Shrink the buffer by advancing its logical start */
465+ self -> ob_start -= growth ;
466+ /*
467+ 0 lo hi old_size
468+ | |<----avail----->|<-----tail------>|
469+ | |<-bytes_len->|<-----tail------>|
470+ 0 new_lo new_hi new_size
471+ */
472+ }
473+ else {
474+ /*
475+ 0 lo hi old_size
476+ | |<----avail----->|<-----tomove------>|
477+ | |<-bytes_len->|<-----tomove------>|
478+ 0 lo new_hi new_size
479+ */
480+ memmove (buf + lo + bytes_len , buf + hi ,
481+ Py_SIZE (self ) - hi );
482+ }
483+ if (PyByteArray_Resize ((PyObject * )self ,
484+ Py_SIZE (self ) + growth ) < 0 ) {
485+ /* Issue #19578: Handling the memory allocation failure here is
486+ tricky here because the bytearray object has already been
487+ modified. Depending on growth and lo, the behaviour is
488+ different.
489+
490+ If growth < 0 and lo != 0, the operation is completed, but a
491+ MemoryError is still raised and the memory block is not
492+ shrinked. Otherwise, the bytearray is restored in its previous
493+ state and a MemoryError is raised. */
462494 if (lo == 0 ) {
463- /* Shrink the buffer by advancing its logical start */
464- self -> ob_start -= growth ;
465- /*
466- 0 lo hi old_size
467- | |<----avail----->|<-----tail------>|
468- | |<-bytes_len->|<-----tail------>|
469- 0 new_lo new_hi new_size
470- */
471- }
472- else {
473- /*
474- 0 lo hi old_size
475- | |<----avail----->|<-----tomove------>|
476- | |<-bytes_len->|<-----tomove------>|
477- 0 lo new_hi new_size
478- */
479- memmove (buf + lo + bytes_len , buf + hi ,
480- Py_SIZE (self ) - hi );
495+ self -> ob_start += growth ;
496+ return -1 ;
481497 }
498+ /* memmove() removed bytes, the bytearray object cannot be
499+ restored in its previous state. */
500+ Py_SIZE (self ) += growth ;
501+ res = -1 ;
482502 }
483- /* XXX(nnorwitz): need to verify this can't overflow! */
484- if (PyByteArray_Resize (
485- (PyObject * )self , Py_SIZE (self ) + growth ) < 0 )
486- return -1 ;
487503 buf = PyByteArray_AS_STRING (self );
488- if (growth > 0 ) {
489- /* Make the place for the additional bytes */
490- /*
491- 0 lo hi old_size
492- | |<-avail->|<-----tomove------>|
493- | |<---bytes_len-->|<-----tomove------>|
494- 0 lo new_hi new_size
495- */
496- memmove (buf + lo + bytes_len , buf + hi ,
497- Py_SIZE (self ) - lo - bytes_len );
504+ }
505+ else if (growth > 0 ) {
506+ if (Py_SIZE (self ) > (Py_ssize_t )PY_SSIZE_T_MAX - growth ) {
507+ PyErr_NoMemory ();
508+ return -1 ;
498509 }
510+
511+ if (PyByteArray_Resize ((PyObject * )self ,
512+ Py_SIZE (self ) + growth ) < 0 ) {
513+ return -1 ;
514+ }
515+ buf = PyByteArray_AS_STRING (self );
516+ /* Make the place for the additional bytes */
517+ /*
518+ 0 lo hi old_size
519+ | |<-avail->|<-----tomove------>|
520+ | |<---bytes_len-->|<-----tomove------>|
521+ 0 lo new_hi new_size
522+ */
523+ memmove (buf + lo + bytes_len , buf + hi ,
524+ Py_SIZE (self ) - lo - bytes_len );
499525 }
500526
501527 if (bytes_len > 0 )
502528 memcpy (buf + lo , bytes , bytes_len );
503- return 0 ;
529+ return res ;
504530}
505531
506532static int
0 commit comments