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 — gh-127716: Fix data race in `memoryview.release()` by weixlu · Pull Request #154770 · python/cpython

Conversation

@weixlu

@weixlu weixlu commented Jul 27, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

As reported in #127716, on no-gil build, several threads calling memoryview.release() on views of the same buffer will cause problem.

Root cause

Let's take a look at memoryview.release()

static void _memory_release(PyMemoryViewObject *self)
{
    assert(get_exports(self) == 0);
    if (self->flags & _Py_MEMORYVIEW_RELEASED)   // (1) test
        return;

    self->flags |= _Py_MEMORYVIEW_RELEASED;      // (2) set
    assert(self->mbuf->exports > 0);
    if (--self->mbuf->exports == 0) {            // (3) non-atomic decrement
        mbuf_release(self->mbuf);
    }
}

Here "test the flag" (1) and "set the flag" (2) are two separate, unsynchronized operations. When mbuf->exports == 1, two threads race like this:

step thread A thread B
test flag (1) sees not released → continues sees not released → continues
set flag (2) sets RELEASED sets RELEASED (again, no-op)
decrement (3) --exports → 0, calls mbuf_release() --exports → -1

Both threads get past the guard, so both run the decrement. As a result, mbuf->exports drops below 0.

Fix

To fix this, we have to make self->flags's test-and-set a single atomic operation, so that exactly one thread wins the transition and performs the decrement. Here I'm using _Py_atomic_or_uint32. It is used in both release entry points:

  • _memory_release() — This code path belongs to the case "Debug build with ASan" in the original issue.
  • mbuf_release() — This code path belongs to the case "Plain debug build (no ASan)"

Testing

  • The reproducer from the original issue no longer aborts (with and without ASan).
  • python -m test test_memoryview passes (with and without GIL).
  • In the default (with-GIL) build, the atomic ops degrade to the original plain ones, so behavior and performance are unchanged.
  • Issue: make memoryview thread safe in free-threading #127716

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@weixlu
pythongh-127716: Fix data race in memoryview.release()
1677fb3
@bedevere-app bedevere-app Bot mentioned this pull request Jul 27, 2026
make memoryview thread safe in free-threading #127716
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Jul 27, 2026
@ayaangazali ayaangazali mentioned this pull request Aug 16, 2026
gh-155606: Increment the managed buffer export count atomically #155882
Closed
@nascheme

nascheme commented Aug 21, 2026

Copy link
Copy Markdown
Member

This would need a fair amount of work before it's ready to merge:

  • Need regression test and NEWS entry.
  • mbuf->exports still has non-atomic updates, e.g. mbuf_add_view() and mbuf_add_incomplete_view() use non-atomic increments. Need to check all operations on the counters to ensure they use the correct atomics or locking.
  • Release and buffer acquisition/access need a locking or equivalent state protocol. Right now, a thread checks if the memory view is released, if not, accesses the buffer. Another thread can call release() between those steps. The new atomic operation only prevents two threads from releasing the same view twice.

GH-155882 fixes the missing atomics on the export increments but doesn't fix the last issue.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme nascheme mentioned this pull request Aug 23, 2026
gh-127716: make memoryview thread-safe in free-threaded build #156248
Merged
@weixlu

weixlu commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

This will be fix in #156248

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@weixlu weixlu closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

awaiting review

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@weixlu @nascheme
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.