From 0bb3befec76eac4829b10fc41abdf045be06d943 Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Sat, 11 Jul 2026 22:21:38 +0800 Subject: [PATCH 1/2] gh-153578: Fix out-of-bounds write in bytearray.extend() with a reentrant __buffer__ bytearray.extend() clamped only the high bound of the append range to the current size after acquiring the argument's buffer, so a __buffer__ that shrinks the bytearray left the low bound past the high bound and ran a negative-size memmove. Clamp the low bound too, matching bytearray.__iadd__. --- Lib/test/test_bytes.py | 20 +++++++++++++++++++ ...-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst | 2 ++ Objects/bytearrayobject.c | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index e211c3d15a4ed2..9a435de1e0ef41 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1799,6 +1799,26 @@ def test_setslice_trap(self): b[8:] = b self.assertEqual(b, bytearray(list(range(8)) + list(range(256)))) + def test_setslice_reentrant_resize(self): + # gh-153578: a buffer argument whose __buffer__ resizes the bytearray + # while the buffer is being acquired must not leave the slice bounds + # with lo > hi, which drove a negative-size memmove (an out-of-bounds + # write) in the setslice path reached through extend(). + class Evil: + def __init__(self, resize): + self.resize = resize + def __buffer__(self, flags): + self.resize() + return memoryview(b'ABCDEFGH') + # clear() during __buffer__: extend appends to the emptied bytearray. + b = bytearray(b'x' * 100) + b.extend(Evil(b.clear)) + self.assertEqual(b, b'ABCDEFGH') + # partial shrink during __buffer__. + b = bytearray(b'x' * 100) + b.extend(Evil(lambda: b.__delitem__(slice(30, None)))) + self.assertEqual(b, b'x' * 30 + b'ABCDEFGH') + def test_iconcat(self): b = bytearray(b"abc") b1 = b diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst new file mode 100644 index 00000000000000..cb98d02fd16973 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst @@ -0,0 +1,2 @@ +Fix a crash in :meth:`bytearray.extend` when the argument's +:meth:`~object.__buffer__` method resizes the bytearray. Patch by tonghuaroot. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 696ddad8efaae5..9295a6d4ff08d2 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -670,8 +670,11 @@ bytearray_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, bytes = vbytes.buf; } + // gh-153578: __buffer__() may have resized self; re-clamp both bounds. if (lo < 0) lo = 0; + else if (lo > Py_SIZE(self)) + lo = Py_SIZE(self); if (hi < lo) hi = lo; if (hi > Py_SIZE(self)) From 5128c85e089eabdcb47a3c57eb13ef0d5811c386 Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Tue, 18 Aug 2026 17:33:14 +0800 Subject: [PATCH 2/2] Frame the NEWS as a concurrency issue and add the grow-during-__buffer__ test --- Lib/test/test_bytes.py | 4 ++++ .../2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 9a435de1e0ef41..70de19e80d296e 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1818,6 +1818,10 @@ def __buffer__(self, flags): b = bytearray(b'x' * 100) b.extend(Evil(lambda: b.__delitem__(slice(30, None)))) self.assertEqual(b, b'x' * 30 + b'ABCDEFGH') + # grow during __buffer__: the data lands at the original end. + b = bytearray(b'x' * 10) + b.extend(Evil(lambda: b.extend(b'y' * 100))) + self.assertEqual(b, b'x' * 10 + b'ABCDEFGH' + b'y' * 100) def test_iconcat(self): b = bytearray(b"abc") diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst index cb98d02fd16973..2d5d4058a04ef2 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-45-00.gh-issue-153578.Qm4Zt9.rst @@ -1,2 +1,3 @@ -Fix a crash in :meth:`bytearray.extend` when the argument's -:meth:`~object.__buffer__` method resizes the bytearray. Patch by tonghuaroot. +Fix an out-of-bounds write in :meth:`bytearray.extend` when the bytearray is +resized while the argument's :meth:`~object.__buffer__` is being acquired, for +example by another thread. Patch by tonghuaroot.