Skip to content

Commit 63662b9

Browse files
committed
gh-141786 Fix missing parent executor during trace
An executor's trace can point to another executor, forming a graph of traces / executors. Sometimes it is possible while recording a trace that the parent executor is freed / invalidated halfway. This leads to the bug described in the issue gh-141786, which if left unfixed could cause a memory leak. This patch checks for the validity of the parent executor as well as allowing JIT from the cold executor. While the cold executor is not linked, it is the executor responsible for creating side traces and we still want to JIT from it.
1 parent 53ec7c8 commit 63662b9

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

Python/ceval.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,9 @@ stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame)
14081408
// Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed
14091409
// to be valid to access.
14101410
if (err <= 0) {
1411-
exit->temperature = restart_backoff_counter(exit->temperature);
1411+
if (exit->executor->vm_data.linked || exit->executor->vm_data.valid) {
1412+
exit->temperature = restart_backoff_counter(exit->temperature);
1413+
}
14121414
}
14131415
else {
14141416
exit->temperature = initial_temperature_backoff_counter();

Python/optimizer.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ _PyOptimizer_Optimize(
140140
}
141141
assert(!interp->compiling);
142142
assert(_tstate->jit_tracer_state.initial_state.stack_depth >= 0);
143+
_PyExitData *exit = _tstate->jit_tracer_state.initial_state.exit;
144+
_PyExecutorObject *cold_executor = _PyExecutor_GetColdExecutor();
145+
if (exit != NULL &&
146+
(!exit->executor->vm_data.linked || !exit->executor->vm_data.valid) &&
147+
exit->executor != cold_executor) {
148+
// gh-141786 Parent executor is either unlinked or invalid - cannot optimize.
149+
return 0;
150+
}
143151
#ifndef Py_GIL_DISABLED
144152
assert(_tstate->jit_tracer_state.initial_state.func != NULL);
145153
interp->compiling = true;
@@ -185,7 +193,6 @@ _PyOptimizer_Optimize(
185193
else {
186194
executor->vm_data.code = NULL;
187195
}
188-
_PyExitData *exit = _tstate->jit_tracer_state.initial_state.exit;
189196
if (exit != NULL) {
190197
exit->executor = executor;
191198
}

0 commit comments

Comments
 (0)