From 1303cf0cf4416008fbdc409bbc11df94bfc2c714 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Tue, 23 Dec 2025 23:35:19 +0000 Subject: [PATCH 1/4] Protect against re-entrant tracer calls --- Python/optimizer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Python/optimizer.c b/Python/optimizer.c index 0f8ddb4ba558d3..435b39405d6e5b 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -138,6 +138,12 @@ _PyOptimizer_Optimize( // return immediately without optimization. return 0; } + if (_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; + } assert(!interp->compiling); assert(_tstate->jit_tracer_state.initial_state.stack_depth >= 0); #ifndef Py_GIL_DISABLED From 9f5f8b5ff0bb90e4cb918c42dfdff786cafa9750 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:36:46 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-12-23-23-36-41.gh-issue-143123.-51gt_.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-23-23-36-41.gh-issue-143123.-51gt_.rst 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. From cdb5d463f94a0f00928934dc3736298cb1f5a39f Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 25 Dec 2025 00:30:23 +0000 Subject: [PATCH 3/4] Stronger check for recursive traces --- Include/internal/pycore_optimizer.h | 2 +- Python/ceval.c | 2 +- Python/optimizer.c | 14 ++++++-------- Python/pystate.c | 2 ++ 4 files changed, 10 insertions(+), 10 deletions(-) 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/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 435b39405d6e5b..7cc8b0396bc10c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -138,12 +138,6 @@ _PyOptimizer_Optimize( // return immediately without optimization. return 0; } - if (_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; - } assert(!interp->compiling); assert(_tstate->jit_tracer_state.initial_state.stack_depth >= 0); #ifndef Py_GIL_DISABLED @@ -1031,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) { @@ -1095,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..4dd1412db4f2ad 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; @@ -1846,6 +1847,7 @@ tstate_delete_common(PyThreadState *tstate, int release_gil) _PyObject_VirtualFree(_tstate->jit_tracer_state.code_buffer, UOP_BUFFER_SIZE); _tstate->jit_tracer_state.code_buffer = NULL; } + _PyJit_ResetTracing(tstate); #endif HEAD_UNLOCK(runtime); From 4e216feb94c2af3a0d7f5f9a0c10fe9f1dba608e Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 25 Dec 2025 01:35:03 +0000 Subject: [PATCH 4/4] fix crash --- Python/pystate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 4dd1412db4f2ad..0ffc641a9029ed 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1847,7 +1847,6 @@ tstate_delete_common(PyThreadState *tstate, int release_gil) _PyObject_VirtualFree(_tstate->jit_tracer_state.code_buffer, UOP_BUFFER_SIZE); _tstate->jit_tracer_state.code_buffer = NULL; } - _PyJit_ResetTracing(tstate); #endif HEAD_UNLOCK(runtime);