From 522563549a49d28e763635c58274a23a6055f041 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 28 Dec 2025 14:30:36 +0200 Subject: [PATCH] gh-143003: Fix possible shared buffer overflow in bytearray.extend() (GH-143086) When __length_hint__() returns 0 for non-empty iterator, the data can be written past the shared 0-terminated buffer, corrupting it. --- Lib/test/test_bytes.py | 17 +++++++++++++++++ ...25-12-23-00-13-02.gh-issue-143003.92g5qW.rst | 2 ++ Objects/bytearrayobject.c | 4 ++-- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-23-00-13-02.gh-issue-143003.92g5qW.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index e0baeece34c..c42c0d4f5e9 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2104,6 +2104,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 00000000000..30df3c53abd --- /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 5262ac20c07..7f09769e12f 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -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);