gh-143003: Fix possible shared buffer overflow in bytearray.extend()

When __length_hint__() returns 0 for non-empty iterator, the data can be
written past the shared 0-terminated buffer, corrupting it.
This commit is contained in:
Serhiy Storchaka 2025-12-23 00:13:37 +02:00
parent 665d2807a0
commit beee2f04f0
3 changed files with 22 additions and 2 deletions

View file

@ -2092,6 +2092,24 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase):
with self.assertRaises(BufferError):
ba.rsplit(evil)
def test_extend_empty_buffer_overflow(self):
# gh-143003
class EvilIter:
def __iter__(self):
return self
def __next__(self):
return next(source)
def __length_hint__(self):
return 0
# Use ASCII digits so float() takes the fast path that expects a NUL terminator.
source = iter(b'42')
ba = bytearray()
ba.extend(EvilIter())
self.assertRaises(ValueError, float, bytearray())
class AssortedBytesTest(unittest.TestCase):
#
# Test various combinations of bytes and bytearray

View file

@ -0,0 +1,2 @@
Fix an overflow of the shared empty buffer in :meth:`bytearray.extend` when
``__length_hint__()`` returns 0 for non-empty iterator.

View file

@ -2223,7 +2223,6 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
Py_DECREF(bytearray_obj);
return NULL;
}
buf[len++] = value;
Py_DECREF(item);
if (len >= buf_size) {
@ -2233,7 +2232,7 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
Py_DECREF(bytearray_obj);
return PyErr_NoMemory();
}
addition = len >> 1;
addition = len ? len >> 1 : 1;
if (addition > PyByteArray_SIZE_MAX - len)
buf_size = PyByteArray_SIZE_MAX;
else
@ -2247,6 +2246,7 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
have invalidated it. */
buf = PyByteArray_AS_STRING(bytearray_obj);
}
buf[len++] = value;
}
Py_DECREF(it);