diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 91687a90a2c073..56bdfe373191d4 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1941,6 +1941,23 @@ def make_case(): 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()) + def test_hex_use_after_free(self): # Prevent UAF in bytearray.hex(sep) with re-entrant sep.__len__. # Regression test for https://github.com/python/cpython/issues/143195. diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-12-23-00-13-02.gh-issue-143003.92g5qW.rst b/Misc/NEWS.d/next/Core and Builtins/2025-12-23-00-13-02.gh-issue-143003.92g5qW.rst new file mode 100644 index 00000000000000..30df3c53abd29f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2025-12-23-00-13-02.gh-issue-143003.92g5qW.rst @@ -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. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 5e29dd8e69d10e..feea0aef276118 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1871,7 +1871,6 @@ bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints) Py_DECREF(bytearray_obj); return NULL; } - buf[len++] = value; Py_DECREF(item); if (len >= buf_size) { @@ -1881,7 +1880,7 @@ bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints) Py_DECREF(bytearray_obj); return PyErr_NoMemory(); } - addition = len >> 1; + addition = len ? len >> 1 : 1; if (addition > PY_SSIZE_T_MAX - len - 1) buf_size = PY_SSIZE_T_MAX; else @@ -1895,6 +1894,7 @@ bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints) have invalidated it. */ buf = PyByteArray_AS_STRING(bytearray_obj); } + buf[len++] = value; } Py_DECREF(it);