@@ -1621,6 +1621,7 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16211621 }
16221622
16231623 Py_ssize_t remaining_length = size - to_take ;
1624+
16241625 // optimization: If taking less than leaving, just copy the small to_take
16251626 // portion out and move ob_start.
16261627 if (to_take < remaining_length ) {
@@ -1642,15 +1643,30 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n)
16421643 memcpy (PyBytes_AS_STRING (remaining ), self -> ob_start + to_take ,
16431644 remaining_length );
16441645
1645- // If the bytes are offset inside the buffer must first align.
1646- if (self -> ob_start != self -> ob_bytes ) {
1647- memmove (self -> ob_bytes , self -> ob_start , to_take );
1648- self -> ob_start = self -> ob_bytes ;
1649- }
1646+ size_t logical_offset = (size_t ) (self -> ob_start - self -> ob_bytes );
1647+ if (logical_offset == 0 || remaining_length == 0 ) {
1648+ // If the bytes are offset inside the buffer must first align.
1649+ if (logical_offset != 0 ) {
1650+ memmove (self -> ob_bytes , self -> ob_start , to_take );
1651+ self -> ob_start = self -> ob_bytes ;
1652+ }
16501653
1651- if (_PyBytes_ResizeKeepOnError (& self -> ob_bytes_object , to_take ) == -1 ) {
1652- Py_DECREF (remaining );
1653- return NULL ;
1654+ if (_PyBytes_ResizeKeepOnError (& self -> ob_bytes_object , to_take ) == -1 ) {
1655+ Py_DECREF (remaining );
1656+ return NULL ;
1657+ }
1658+ }
1659+ else {
1660+ // Using memmove() would be unsafe, since _PyBytes_ResizeKeepOnError()
1661+ // failure code path would be unable to restore the bytearray to its
1662+ // previous state.
1663+ PyObject * resized = PyBytes_FromStringAndSize (NULL , to_take );
1664+ if (resized == NULL ) {
1665+ Py_DECREF (remaining );
1666+ return NULL ;
1667+ }
1668+ memcpy (PyBytes_AS_STRING (resized ), self -> ob_start , to_take );
1669+ Py_SETREF (self -> ob_bytes_object , resized );
16541670 }
16551671
16561672 // Point the bytearray towards the buffer with the remaining data.
0 commit comments