diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 36efab51878141..d455c0a25120db 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -6016,6 +6016,28 @@ def f1(): """), PYTHON_JIT="1") self.assertEqual(result[0].rc, 0, result) + def test_157875_rewound_trace_reference_leak(self): + # https://github.com/python/cpython/issues/157875 + import weakref + + def run(): + class C: + def __iter__(self): + return self + + def __next__(self): + raise StopIteration + + obj = C() + for _ in range(TIER2_THRESHOLD): + for _ in obj: + pass + return weakref.ref(C) + + ref = run() + gc.collect() + self.assertIsNone(ref()) + def test_144068_daemon_thread_jit_cleanup(self): result = script_helper.run_python_until_end('-c', textwrap.dedent(""" import threading diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-00-00.gh-issue-157875.7Qn4Jp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-00-00.gh-issue-157875.7Qn4Jp.rst new file mode 100644 index 00000000000000..22b1a17fa7bca4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-00-00.gh-issue-157875.7Qn4Jp.rst @@ -0,0 +1,2 @@ +Fix a reference leak in the JIT when a trace is rewound after encountering +unsupported bytecode. diff --git a/Python/optimizer.c b/Python/optimizer.c index e05adb344c8d06..4ae72304c16206 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -789,6 +789,9 @@ _PyJit_translate_single_bytecode_to_trace( { _PyUOpInstruction *curr = uop_buffer_last(trace); while (curr->opcode != _SET_IP && uop_buffer_length(trace) > 2) { + if (_PyUop_Flags[curr->opcode] & HAS_RECORDS_VALUE_FLAG) { + Py_XDECREF((PyObject *)(uintptr_t)curr->operand0); + } trace->next--; curr = uop_buffer_last(trace); }