Repository navigation
Closed
Labels
3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixes3.16new features, bugs and security fixesnew features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
To reproduce, run:
ba = bytearray(b"abc")
ba.take_bytes(2)
ba[0] = 0x42
print(b'c')However, this does not print b'c' as you'd expect, instead you get:
$ python3.15 /tmp/repro.py
b'B'
This is becasue take_bytes() builds the leftover buffer with PyBytes_FromStringAndSize, which for one remaining character returns the immortal, process-wide one-character bytes singleton instead of a fresh allocation:
cpython/Objects/bytearrayobject.c
Lines 1622 to 1624 in 14a93f4
| // Copy remaining bytes to a new bytes. | |
| PyObject *remaining = PyBytes_FromStringAndSize(self->ob_start + to_take, | |
| remaining_length); |
The bytearray then installs that singleton as its mutable ob_bytes_object, so any write to it modifies the shared singleton that every b'c' refers to.
CPython versions tested on:
3.15, CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-156995: Fix
bytearray.take_bytes()corrupting shared single-byte bytes objects #156996 - [3.15] gh-156995: Fix
bytearray.take_bytes()corrupting shared single-byte singletons (GH-156996) #157260 - gh-156995: Add caution around API behavior change #157292
- [3.14] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) #157373
- [3.13] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) (#157373) #157436
- [3.14] gh-156995: Fix typo in the _PyBytes_Resize() NEWS entry #157477
Metadata
Metadata
Assignees
Labels
3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixes3.16new features, bugs and security fixesnew features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Projects
- StatusShow more project fieldsDone
Activity
encukou commentedon Sep 9, 2026
Marking as a potential release blocker
gh-156995: Fix `bytearray.take_bytes()` corrupting shared single-byte…
[3.15] gh-156995: Fix `bytearray.take_bytes()` corrupting shared sing…
cmaloney commentedon Sep 11, 2026
Proposing adding a docs caution for
PyUnstable_Object_IsUniquelyReferencedbehavior between GIL-enabled and free-threaded builds: #1572922 remaining items
cmaloney commentedon Sep 12, 2026
Reopening as 3.14's
_PyBytes_Resizeshould get this same fix (bytearraydoesn't usebytesbut free threaded subtle bug exists). This no longer blocks 3.15's release.pythongh-156995: Fix `bytearray.take_bytes()` corrupting shared singl…
vstinner commentedon Sep 12, 2026
I wrote PR gh-157371 to add assertions in debug mode to make sure that a bytes object is mutable.
pythongh-156995: Fix _PyBytes_Resize() in Free Threading (python#156996)
[3.14] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) (#…
[3.14] pythongh-156995: Fix _PyBytes_Resize() in Free Threading (pyth…
[3.13] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) (#…
cmaloney commentedon Sep 14, 2026
I like the new IsMutable asserts, really clear on what is being checked and why. Closing this as the backports have been merged.
pythongh-156995: Fix typo in the _PyBytes_Resize() NEWS entry
gh-156995: Fix typo in the _PyBytes_Resize() NEWS entry (#157477)
pythongh-156995: Fix `bytearray.take_bytes()` corrupting shared singl…
vstinner commentedon Sep 15, 2026
I wrote PR gh-157572 to detect such silent data corruption: in debug mode at Python exit, check if all immutable singletons have been modified.