Skip to content

gh-144981: Make PyUnstable_Code_SetExtra/GetExtra thread-safe#144980

Open
yoney wants to merge 2 commits intopython:mainfrom
yoney:extra
Open

gh-144981: Make PyUnstable_Code_SetExtra/GetExtra thread-safe#144980
yoney wants to merge 2 commits intopython:mainfrom
yoney:extra

Conversation

@yoney
Copy link
Contributor

@yoney yoney commented Feb 18, 2026

  • PyUnstable_Code_GetExtra and PyUnstable_Code_SetExtra had no thread-safety. Concurrent calls could cause data races.
  • GetExtra is performance-sensitive for the use cases like JIT . It now uses an acquire load of co_extra and plain reads of the immutable published buffer.
  • SetExtra uses a per-object critical section and copy-on-write: it always allocates a new buffer, copies existing slots, and publishes with a release store. Old buffers are freed via _PyMem_FreeDelayed in free-threaded builds.
  • PyUnstable_Eval_RequestCodeExtraIndex is now protected by interp->code_state.mutex.
  • Added free-threading tests for concurrent RequestCodeExtraIndex, SetExtra, and GetExtra.

The new tests exercise the concurrent paths and a free-threaded TSAN build without the fix crashes/emits warnings.

cc: @DinoV @colesbury

@yoney yoney changed the title Make PyUnstable_Code_SetExtra/GetExtra thread-safe gh-144981: Make PyUnstable_Code_SetExtra/GetExtra thread-safe Feb 18, 2026
@yoney yoney marked this pull request as ready for review February 18, 2026 23:22
@yoney yoney requested a review from markshannon as a code owner February 18, 2026 23:22
o->co_extra = co_extra;
Py_BEGIN_CRITICAL_SECTION(o);

_PyCodeObjectExtra *old_extra = (_PyCodeObjectExtra *) o->co_extra;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably still needs to be relaxed as it races w/ the get

co_extra->ce_extras[i] = NULL;
}

if (old_extra != NULL && index < old_size &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we want to grab this value and move the free outside of the critical section?

// Lock-free read; pairs with release store in SetExtra.
_PyCodeObjectExtra *co_extra = FT_ATOMIC_LOAD_PTR_ACQUIRE(o->co_extra);
if (co_extra != NULL && index < co_extra->ce_size) {
*extra = co_extra->ce_extras[index];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want a relaxed read here too as it's racing with the writer

Py_ssize_t new_size = old_size > index ? old_size : user_count;
assert(new_size > 0 && new_size > index);

// Free-threaded builds require copy-on-write to avoid mutating
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be run a if (new_size != old_size)? I don't think we need to copy the whole thing for this to work lock free if we're using the right atomics when reading the values.

}
}

co_extra->ce_extras[index] = extra;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this should probably be a relaxed store

@bedevere-app
Copy link

bedevere-app bot commented Feb 18, 2026

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments