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:
|
// 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
Bug report
Bug description:
To reproduce, run:
However, this does not print
b'c'as you'd expect, instead you get:This is becasue
take_bytes()builds the leftover buffer withPyBytes_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
The
bytearraythen installs that singleton as its mutableob_bytes_object, so any write to it modifies the shared singleton that everyb'c'refers to.CPython versions tested on:
3.15, CPython main branch
Operating systems tested on:
Linux
Linked PRs
bytearray.take_bytes()corrupting shared single-byte bytes objects #156996