Skip to content

Commit 2984024

Browse files
authored
gh-144068: fix JIT tracer memory leak when daemon thread exits (GH-144077)
1 parent 6f57914 commit 2984024

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,6 +3889,29 @@ def __next__(self):
38893889
"""), PYTHON_JIT="1", PYTHON_JIT_STRESS="1")
38903890
self.assertEqual(result[0].rc, 0, result)
38913891

3892+
def test_144068_daemon_thread_jit_cleanup(self):
3893+
result = script_helper.run_python_until_end('-c', textwrap.dedent("""
3894+
import threading
3895+
import time
3896+
3897+
def hot_loop():
3898+
end = time.time() + 5.0
3899+
while time.time() < end:
3900+
pass
3901+
3902+
# Create a daemon thread that will be abandoned at shutdown
3903+
t = threading.Thread(target=hot_loop, daemon=True)
3904+
t.start()
3905+
3906+
time.sleep(0.1)
3907+
"""), PYTHON_JIT="1", ASAN_OPTIONS="detect_leaks=1")
3908+
self.assertEqual(result[0].rc, 0, result)
3909+
stderr = result[0].err.decode('utf-8', errors='replace')
3910+
self.assertNotIn('LeakSanitizer', stderr,
3911+
f"Memory leak detected by ASan:\n{stderr}")
3912+
self.assertNotIn('_PyJit_TryInitializeTracing', stderr,
3913+
f"JIT tracer memory leak detected:\n{stderr}")
3914+
38923915
def global_identity(x):
38933916
return x
38943917

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix JIT tracer memory leak, ensure the JIT tracer state is freed when daemon threads are cleaned up during interpreter shutdown.

Python/pystate.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,10 @@ PyThreadState_Clear(PyThreadState *tstate)
18431843

18441844
_PyThreadState_ClearMimallocHeaps(tstate);
18451845

1846+
#ifdef _Py_TIER2
1847+
_PyJit_TracerFree((_PyThreadStateImpl *)tstate);
1848+
#endif
1849+
18461850
tstate->_status.cleared = 1;
18471851

18481852
// XXX Call _PyThreadStateSwap(runtime, NULL) here if "current".

0 commit comments

Comments
 (0)