gh-151436: Fix missing tstate->last_profiled_frame updates (#151437)

This commit is contained in:
Maurycy Pawłowski-Wieroński
2026-06-17 22:49:23 +02:00
committed by GitHub
parent eff805b7a7
commit a8d74c062f
8 changed files with 33 additions and 8 deletions
+2
View File
@@ -1860,6 +1860,7 @@ dummy_func(
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
_PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous);
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
@@ -5874,6 +5875,7 @@ dummy_func(
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev);
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
+2 -8
View File
@@ -1974,15 +1974,8 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
void
_PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
{
// Update last_profiled_frame for remote profiler frame caching.
// By this point, tstate->current_frame is already set to the parent frame.
// Only update if we're popping the exact frame that was last profiled.
// This avoids corrupting the cache when transient frames (called and returned
// between profiler samples) update last_profiled_frame to addresses the
// profiler never saw.
if (tstate->last_profiled_frame != NULL && tstate->last_profiled_frame == frame) {
tstate->last_profiled_frame = tstate->current_frame;
}
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, tstate->current_frame);
if (frame->owner == FRAME_OWNED_BY_THREAD) {
clear_thread_frame(tstate, frame);
@@ -2008,6 +2001,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
_PyFrame_Initialize(tstate, frame, func, locals, code, 0, previous);
if (initialize_locals(tstate, func_obj, frame->localsplus, args, argcount, kwnames)) {
assert(frame->owner == FRAME_OWNED_BY_THREAD);
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, tstate->current_frame);
clear_thread_frame(tstate, frame);
return NULL;
}
+2
View File
@@ -9340,6 +9340,7 @@
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
_PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous);
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
@@ -20346,6 +20347,7 @@
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev);
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
+3
View File
@@ -7938,6 +7938,7 @@
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
_PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous);
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
@@ -10997,6 +10998,7 @@
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev);
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
@@ -13026,6 +13028,7 @@
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
_PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous);
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;