Skip to content

bytearray.take_bytes() can corrupt shared single-byte bytes objects #156995

Description

@StanFromIreland

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions