diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 79c7f530b8ae89..8cf529c6eb4439 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3792,6 +3792,29 @@ def __next__(self): """), PYTHON_JIT="1", PYTHON_JIT_STRESS="1") self.assertEqual(result[0].rc, 0, result) + def test_144068_daemon_thread_jit_cleanup(self): + result = script_helper.run_python_until_end('-c', textwrap.dedent(""" + import threading + import time + + def hot_loop(): + end = time.time() + 5.0 + while time.time() < end: + pass + + # Create a daemon thread that will be abandoned at shutdown + t = threading.Thread(target=hot_loop, daemon=True) + t.start() + + time.sleep(0.1) + """), PYTHON_JIT="1", ASAN_OPTIONS="detect_leaks=1") + self.assertEqual(result[0].rc, 0, result) + stderr = result[0].err.decode('utf-8', errors='replace') + self.assertNotIn('LeakSanitizer', stderr, + f"Memory leak detected by ASan:\n{stderr}") + self.assertNotIn('_PyJit_TryInitializeTracing', stderr, + f"JIT tracer memory leak detected:\n{stderr}") + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst new file mode 100644 index 00000000000000..b3e5db64a368b3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst @@ -0,0 +1 @@ +Fix JIT tracer memory leak, ensure the JIT tracer state is freed when daemon threads are cleaned up during interpreter shutdown. diff --git a/Python/pystate.c b/Python/pystate.c index 86dee70734a097..0993f9f906153d 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1836,6 +1836,10 @@ PyThreadState_Clear(PyThreadState *tstate) _PyThreadState_ClearMimallocHeaps(tstate); +#ifdef _Py_TIER2 + _PyJit_TracerFree((_PyThreadStateImpl *)tstate); +#endif + tstate->_status.cleared = 1; // XXX Call _PyThreadStateSwap(runtime, NULL) here if "current".