Skip to content

Commit a25147b

Browse files
committed
gh-149110: Fix memory ordering in take_ownership() for f_frame publication
1 parent 5c7f3aa commit a25147b

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

Objects/frameobject.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,10 +2399,15 @@ PyFrameObject*
23992399
PyFrame_GetBack(PyFrameObject *frame)
24002400
{
24012401
assert(frame != NULL);
2402-
assert(!_PyFrame_IsIncomplete(frame->f_frame));
2402+
/* Use an acquire load so that if we observe the new f_frame pointer
2403+
* published by take_ownership()'s release store, we also observe
2404+
* new_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT. */
2405+
_PyInterpreterFrame *f_frame =
2406+
(_PyInterpreterFrame *)_Py_atomic_load_ptr_acquire(&frame->f_frame);
2407+
assert(!_PyFrame_IsIncomplete(f_frame));
24032408
PyFrameObject *back = frame->f_back;
24042409
if (back == NULL) {
2405-
_PyInterpreterFrame *prev = frame->f_frame->previous;
2410+
_PyInterpreterFrame *prev = f_frame->previous;
24062411
prev = _PyFrame_GetFirstComplete(prev);
24072412
if (prev) {
24082413
back = _PyFrame_GetFrameObject(prev);

Python/frame.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
6969
* observes the new f_frame pointer also sees owner = FRAME_OWNED_BY_FRAME_OBJECT,
7070
* causing _PyFrame_IsIncomplete() to short-circuit to false. */
7171
new_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
72-
f->f_frame = new_frame;
72+
/* Publish f_frame with a release store so that any concurrent reader
73+
* doing an acquire load of f_frame is guaranteed to also observe
74+
* new_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT (written above),
75+
* satisfying the C11 happens-before relationship. */
76+
_Py_atomic_store_ptr_release(&f->f_frame, new_frame);
7377
assert(!_PyFrame_IsIncomplete(new_frame));
7478
assert(f->f_back == NULL);
7579
_PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);

0 commit comments

Comments
 (0)