From 13510c7a72e18d66f5ba8912e53ff1cae20b292e Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 6 Oct 2026 12:56:19 -0700 Subject: [PATCH 1/3] gh-158928: Fix overflow in bytearray.__init__ from an iterator Passing an iterator to `bytearray.__init__` didn't take into account that iterating that iterator could modify the bytearray position and `ob_start`. When that happened the iterator would write beyond the end of the allocation. Update the "enough space" check to account for `ob_start`. The assignment always included it. Add an assert after append that the offsets line up as expected. Co-Authored-By: Claude Opus 4.8 --- Lib/test/test_bytes.py | 16 ++++++++++++++++ ...26-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst | 2 ++ Objects/bytearrayobject.c | 17 +++++++++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 96190a7f582170..4d0c615fd09b11 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2085,6 +2085,22 @@ def g(): alloc = b.__alloc__() self.assertGreater(alloc, len(b)) + def test_init_from_iterator_with_offset(self): + # gh-158928: Inserting form an iterator in __init__ needs to take into + # account if there is a start offset. + b = bytearray() + def iterator_which_resets(): + # __init__ reset ob_start. Make it an offset inside by allocating + # then doing fast prefix delete. + nonlocal b + b.resize(200) + del b[:100] + # Fill remaining already allocated space + yield from b'A' * 100 + # Fill to end. Used to land out of bounds and crash. + b.__init__(iterator_which_resets()) + self.assertEqual(b, bytes(100) + b'A' * 100) + def test_extend(self): orig = b'hello' a = bytearray(orig) diff --git a/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst b/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst new file mode 100644 index 00000000000000..e18ab34a896d8e --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst @@ -0,0 +1,2 @@ +Fix buffer overflow in :meth:`bytearray.__init__` when initializing from an +iterator. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 496d04a1704d46..e4954e750763aa 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1158,17 +1158,26 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, /* Interpret it as an int (__index__) */ rc = _getbytevalue(item, &value); Py_DECREF(item); - if (!rc) + if (!rc) { goto error; + } + + /* Append the byte. - /* Append the byte */ - if (Py_SIZE(self) + 1 < self->ob_alloc) { + Iterators are arbitrary code which could modify the bytearray so + this must always re-calculate if there is enough space(gh-158928). */ + Py_ssize_t needed = + self->ob_start - self->ob_bytes + Py_SIZE(self) + 1; + if (needed < self->ob_alloc) { Py_SET_SIZE(self, Py_SIZE(self) + 1); bytearray_write_trailing_null_byte(self); } - else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0) + else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0) { goto error; + } PyByteArray_AS_STRING(self)[Py_SIZE(self)-1] = value; + assert(self->ob_start - self->ob_bytes + Py_SIZE(self) <= + self->ob_alloc); } /* Clean up and return success */ From 9532fd39cfc19de71f152772b0625846ed9da8fb Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 6 Oct 2026 19:29:06 -0700 Subject: [PATCH 2/3] gh-158928: Fix NEWS reference for bytearray.__init__ --- .../Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst b/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst index e18ab34a896d8e..2b9597c5ed94f3 100644 --- a/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst +++ b/Misc/NEWS.d/next/Security/2026-10-06-12-30-00.gh-issue-158928.Zd9Ybv.rst @@ -1,2 +1,2 @@ -Fix buffer overflow in :meth:`bytearray.__init__` when initializing from an +Fix a buffer overflow when initializing a :class:`bytearray` from an iterator. From 176261bafa23a25518680f12be7e0c112fb2a13d Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Wed, 7 Oct 2026 10:42:16 -0700 Subject: [PATCH 3/3] Better comment formatting --- Objects/bytearrayobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index e4954e750763aa..418f37e861e9a5 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1164,8 +1164,8 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, /* Append the byte. - Iterators are arbitrary code which could modify the bytearray so - this must always re-calculate if there is enough space(gh-158928). */ + gh-158928: Iterators are arbitrary code which could modify the + bytearray so this must re-calculate if there is enough space(). */ Py_ssize_t needed = self->ob_start - self->ob_bytes + Py_SIZE(self) + 1; if (needed < self->ob_alloc) {