diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9c9135411f9078..ead14ab755b49b 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3194,6 +3194,48 @@ class B: ... for i in range(TIER2_THRESHOLD * 10): f1() + def test_143183(self): + # https://github.com/python/cpython/issues/143183 + + result = script_helper.run_python_until_end('-c', textwrap.dedent(f""" + def f1(): + class AsyncIter: + def __init__(self): + self.limit = 0 + self.count = 0 + + def __aiter__(self): + return self + + async def __anext__(self): + if self.count >= self.limit: + ... + self.count += 1j + + class AsyncCtx: + async def async_for_driver(): + try: + for _ in range({TIER2_THRESHOLD}): + try: + async for _ in AsyncIter(): + ... + except TypeError: + ... + except Exception: + ... + + c = async_for_driver() + while True: + try: + c.send(None) + except StopIteration: + break + + for _ in range({TIER2_THRESHOLD // 40}): + f1() + """), PYTHON_JIT="1") + self.assertEqual(result[0].rc, 0, result) + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst new file mode 100644 index 00000000000000..bee2eb672e8813 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst @@ -0,0 +1 @@ +Fix a bug in the JIT when dealing with unsupported control-flow or operations. diff --git a/Python/optimizer.c b/Python/optimizer.c index 5e97f20f869efd..e55dd7bab7ea04 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -625,6 +625,7 @@ _PyJit_translate_single_bytecode_to_trace( int trace_length = _tstate->jit_tracer_state.prev_state.code_curr_size; _PyUOpInstruction *trace = _tstate->jit_tracer_state.code_buffer; int max_length = _tstate->jit_tracer_state.prev_state.code_max_size; + int exit_op = stop_tracing_opcode == 0 ? _EXIT_TRACE : stop_tracing_opcode; _Py_CODEUNIT *this_instr = _tstate->jit_tracer_state.prev_state.instr; _Py_CODEUNIT *target_instr = this_instr; @@ -691,8 +692,10 @@ _PyJit_translate_single_bytecode_to_trace( } if (stop_tracing_opcode != 0) { - ADD_TO_TRACE(stop_tracing_opcode, 0, 0, target); - goto done; + // gh-143183: It's important we rewind to the last known proper target. + // The current target might be garbage as stop tracing usually indicates + // we are in something that we can't trace. + goto unsupported; } DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level); @@ -738,7 +741,7 @@ _PyJit_translate_single_bytecode_to_trace( int32_t old_target = (int32_t)uop_get_target(curr); curr++; trace_length++; - curr->opcode = _EXIT_TRACE; + curr->opcode = exit_op; curr->format = UOP_FORMAT_TARGET; curr->target = old_target; }