GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Data race between `resize_buffer_lock_held` and `_Py_DecRefShared` on a shared `BytesIO` buffer · Issue #151640 · python/cpython

Data race between resize_buffer_lock_held and _Py_DecRefShared on a shared BytesIO buffer #151640

New issue
Copy link
New issue
Copy link
Closed
Closed
Data race between resize_buffer_lock_held and _Py_DecRefShared on a shared BytesIO buffer#151640
Copy link
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@Naserume
Naserume
opened on Jun 18, 2026
Issue body actions

Bug report

Bug description:

In the free-threaded build, a whole-buffer BytesIO.read() returns self->buf by reference (Py_NewRef) instead of a copy,

cpython/Modules/_io/bytesio.c

Lines 432 to 437 in 9e863fa

if (size > 1 &&
self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
self->pos += size;
return Py_NewRef(self->buf);
}

so resize_buffer_lock_held() can reallocate that same self->buf in place (_PyBytes_Resize)

cpython/Modules/_io/bytesio.c

Lines 171 to 178 in 9e863fa

if (SHARED_BUF(self)) {
if (unshare_buffer_lock_held(self, alloc) < 0)
return -1;
}
else {
if (_PyBytes_Resize(&self->buf, alloc) < 0)
return -1;
}

while another thread concurrently decrefs the read-returned reference (_Py_DecRefShared), racing on the same buffer object without synchronization.

Reproducer:

import io
from threading import Thread, Barrier

shared = io.BytesIO(b'x' * 64)
N_W, N_R = 2, 8
barrier = Barrier(N_W + N_R)

def writer():
    barrier.wait()
    for i in range(20000):
        try:
            shared.seek(0)
            shared.write(b'a' * (64 + (i & 63)))
        except Exception:
            pass

def reader():
    barrier.wait()
    for _ in range(20000):
        try:
            shared.seek(0)
            shared.read()
        except Exception:
            pass

if __name__ == "__main__":
    threads = [Thread(target=writer) for _ in range(N_W)]
    threads += [Thread(target=reader) for _ in range(N_R)]
    for t in threads: t.start()
    for t in threads: t.join()

TSAN Report:

==================
WARNING: ThreadSanitizer: data race (pid=2292869)
  Read of size 8 at 0x7fffbc080190 by thread T2:
    #0 _PyObject_MiRealloc /cpython/Objects/obmalloc.c:360:13 
    #1 PyObject_Realloc /cpython/Objects/obmalloc.c:1731:12 
    #2 _PyBytes_Resize /cpython/Objects/bytesobject.c:3389:9 
    #3 resize_buffer_lock_held /cpython/./Modules/_io/bytesio.c:176:13 
    #4 write_bytes_lock_held /cpython/./Modules/_io/bytesio.c:216:13 
    #5 _io_BytesIO_write_impl /cpython/./Modules/_io/bytesio.c:782:20 
    #6 bytesio_setstate_lock_held /cpython/./Modules/_io/bytesio.c:927:14 
    #7 bytesio_setstate /cpython/./Modules/_io/bytesio.c:980:11 
    #8 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:4261:35 
    ...
  Previous atomic write of size 8 at 0x7fffbc080190 by thread T8:
    #0 _Py_atomic_compare_exchange_ssize /cpython/./Include/cpython/pyatomic_gcc.h:130:10 
    #1 _Py_DecRefSharedIsDead /cpython/Objects/object.c:406:15 
    #2 _Py_DecRefSharedDebug /cpython/Objects/object.c:425:9 
    #3 _Py_DecRefShared /cpython/Objects/object.c:433:5 
    #4 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h 
    ...
SUMMARY: ThreadSanitizer: data race /cpython/Objects/obmalloc.c:360:13 in _PyObject_MiRealloc

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

  • gh-151640: Track sharing of BytesIO buffer in free-threaded builds #151651
  • [3.15] gh-151640: Track sharing of BytesIO buffer in free-threaded builds (GH-151651) #153151
  • [3.14] gh-151640: Track sharing of BytesIO buffer in free-threaded builds (GH-151651) #153153

Activity

  1. Naserume
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Jun 18, 2026
  2. pedramkarimii
    added 2 commits that reference this issue on Jun 18, 2026

    pythongh-151640: add NEWS entry

    96dfcb7

    pythongh-151640: fix NEWS entry filename

    918fb1c
  3. ZeroIntensity
    added
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    topic-free-threading
    on Jun 18, 2026
  4. pedramkarimii
    added a commit that references this issue on Jun 19, 2026

    pythongh-151640: simplify BytesIO exports checks

    15cf615
  5. pedramkarimii
    added 11 commits that reference this issue on Jun 27, 2026

    pythongh-151640: avoid sharing BytesIO buffer in free-threaded builds

    66b0fd8

    pythongh-151640: add NEWS entry

    8c0ad2d

    pythongh-151640: fix NEWS entry filename

    29ff0e4

    pythongh-151640: simplify BytesIO exports checks

    0359497

    pythongh-151640: avoid sharing BytesIO buffer in free-threaded builds

    f70aef9

    pythongh-151640: add NEWS entry

    e66d2fb

    pythongh-151640: fix NEWS entry filename

    4bd5bda

    pythongh-151640: simplify BytesIO exports checks

    82e72df

    pythongh-151640: simplify BytesIO exports checks

    b26fbb8

    pythongh-151640: simplify BytesIO exports checks

    33bc6c8

    pythongh-151640: Track sharing of BytesIO buffer in free-threaded builds

    367b372
  6. ZeroIntensity
    added a commit that references this issue on Jul 6, 2026

    gh-151640: Track sharing of `BytesIO` buffer in free-threaded builds (G…

    881a13a
  7. nascheme
    added 2 commits that reference this issue on Jul 9, 2026

    [3.15] gh-151640: Track sharing of `BytesIO` buffer in free-threaded …

    3e19df0

    [3.14] gh-151640: Track sharing of `BytesIO` buffer in free-threaded …

    11c8bf7
  8. nascheme commented on Jul 9, 2026

    @nascheme
    nascheme
    on Jul 9, 2026
    Member
    More actions

    I think this could be closed now. I fixed the trivial issues with the backports for 3.14 and 3.15. Thanks for the PR!

  9. ZeroIntensity
    closed this as completedon Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.