diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 6a0fc1a59e7965..005da63f5afba8 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -354,7 +354,7 @@ _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, int oparg); -void _PyJit_FinalizeTracing(PyThreadState *tstate); +void _PyJit_ResetTracing(PyThreadState *tstate); void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj); diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-23-23-36-41.gh-issue-143123.-51gt_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-23-23-36-41.gh-issue-143123.-51gt_.rst new file mode 100644 index 00000000000000..04523bdb615bfe --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-23-23-36-41.gh-issue-143123.-51gt_.rst @@ -0,0 +1 @@ +Protect the JIT against recursive tracing. diff --git a/Python/ceval.c b/Python/ceval.c index 924afaa97443cb..5562aea3364c51 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1486,7 +1486,7 @@ stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame) exit->temperature = initial_temperature_backoff_counter(); } } - _PyJit_FinalizeTracing(tstate); + _PyJit_ResetTracing(tstate); return err; } #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 0f8ddb4ba558d3..7cc8b0396bc10c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1025,7 +1025,11 @@ _PyJit_TryInitializeTracing( _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; // A recursive trace. // Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces. - if (_tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_EMPTY) { + if (_tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_EMPTY || + _tstate->jit_tracer_state.initial_state.func != NULL) { + // gh-143123: It is possible for another function to finalize the current + // tracer's state while tracing. This might happen in a + // Python -> C -> Python call. return 0; } if (oparg > 0xFFFF) { @@ -1089,7 +1093,7 @@ _PyJit_TryInitializeTracing( } Py_NO_INLINE void -_PyJit_FinalizeTracing(PyThreadState *tstate) +_PyJit_ResetTracing(PyThreadState *tstate) { _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; Py_CLEAR(_tstate->jit_tracer_state.initial_state.code); diff --git a/Python/pystate.c b/Python/pystate.c index cf55297cf8d94e..0ffc641a9029ed 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1526,6 +1526,7 @@ init_threadstate(_PyThreadStateImpl *_tstate, #ifdef _Py_TIER2 _tstate->jit_tracer_state.code_buffer = NULL; + _PyJit_ResetTracing(tstate); #endif tstate->delete_later = NULL;