Skip to content

gh-149110: Fix race in _PyFrame_IsIncomplete for FRAME_OWNED_BY_FRAME… - #156001

Open
BHUVANSH855 wants to merge 2 commits into
python:mainfrom
BHUVANSH855:gh-149110
Open

gh-149110: Fix race in _PyFrame_IsIncomplete for FRAME_OWNED_BY_FRAME…#156001
BHUVANSH855 wants to merge 2 commits into
python:mainfrom
BHUVANSH855:gh-149110

Conversation

@BHUVANSH855

@BHUVANSH855 BHUVANSH855 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

_PyFrame_IsIncomplete was checking instr_ptr against a TLBC slot on
frames already owned by a frame object, which races with take_ownership()
when another thread walks frame.f_back (e.g. via pdb).

Fix:

  • Short-circuit _PyFrame_IsIncomplete for FRAME_OWNED_BY_FRAME_OBJECT
    frames — take_ownership() already guarantees they're complete
  • Fix publication order in take_ownership() so owner is set before
    f->f_frame is visible to concurrent readers
  • Use atomic release/acquire for co_tlbc->entries[idx] writes/reads

Added a regression test in test_free_threading/test_frame.py.

Fixes issue #149110

Comment thread Python/frame.c
new_frame->instr_ptr =
_PyFrame_GetBytecode(new_frame) + code->_co_firsttraceable + 1;
}
/* Set owner BEFORE updating f->f_frame so any concurrent reader that

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does the C memory model guarantee this?
Why can't another thread see f->f_frame = new_frame before new_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, plain C stores provide no ordering guarantee. Fixed in the follow-up commit: take_ownership() now uses _Py_atomic_store_ptr_release() to publish f->f_frame, and PyFrame_GetBack() uses _Py_atomic_load_ptr_acquire() to read it. This establishes the required C11 happens-before relationship — any reader that observes the new f_frame pointer is guaranteed to also observe new_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT.

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