]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-144068: fix JIT tracer memory leak when daemon thread exits (GH-144077)
authorHai Zhu <haiizhu@outlook.com>
Sat, 24 Jan 2026 09:43:01 +0000 (17:43 +0800)
committerGitHub <noreply@github.com>
Sat, 24 Jan 2026 09:43:01 +0000 (09:43 +0000)
Lib/test/test_capi/test_opt.py
Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst [new file with mode: 0644]
Python/pystate.c

index da0d4078c9f5ed9e889512ed80795e58647c0b91..f224984777500ab528401742aaff097a132c62a3 100644 (file)
@@ -3889,6 +3889,29 @@ class TestUopsOptimization(unittest.TestCase):
         """), 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 (file)
index 0000000..b3e5db6
--- /dev/null
@@ -0,0 +1 @@
+Fix JIT tracer memory leak, ensure the JIT tracer state is freed when daemon threads are cleaned up during interpreter shutdown.
index 19f1245d60a2f8fb9b925d2bf1ef30deda33bf08..a8f37bedc812472687a9a6a237db9fd6a902206a 100644 (file)
@@ -1843,6 +1843,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".