https://github.com/python/cpython/commit/48b7d75aaf0206c80813c3325fd4021cd6b99e2b
commit: 48b7d75aaf0206c80813c3325fd4021cd6b99e2b
branch: 3.14
author: Mikhail Efimov <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2025-11-13T16:11:57Z
summary:

[3.14] gh-140936: Fix JIT assertion crash at finalization if some generator is 
alive (GH-140969) (GH-141494)

gh-140936: Fix JIT assertion crash at finalization if some generator is alive 
(GH-140969)

files:
M Lib/test/test_capi/test_opt.py
M Python/optimizer.c

diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index c74c8ee0eef8e2..1860325cba616d 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1972,6 +1972,26 @@ def testfunc(n):
         assert ex is not None
         """))
 
+    def test_interpreter_finalization_with_generator_alive(self):
+        script_helper.assert_python_ok("-c", textwrap.dedent("""
+            import sys
+            t = tuple(range(%d))
+            def simple_for():
+                for x in t:
+                    x
+
+            def gen():
+                try:
+                    yield
+                except:
+                    simple_for()
+
+            sys.settrace(lambda *args: None)
+            simple_for()
+            g = gen()
+            next(g)
+        """ % _testinternalcapi.SPECIALIZATION_THRESHOLD))
+
 
 def global_identity(x):
     return x
diff --git a/Python/optimizer.c b/Python/optimizer.c
index e2b6adfab595f2..6679eecd648a85 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -116,7 +116,14 @@ _PyOptimizer_Optimize(
     _PyExecutorObject **executor_ptr, int chain_depth)
 {
     _PyStackRef *stack_pointer = frame->stackpointer;
-    assert(_PyInterpreterState_GET()->jit);
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    if (!interp->jit) {
+        // gh-140936: It is possible that interp->jit will become false during
+        // interpreter finalization. However, the specialized JUMP_BACKWARD_JIT
+        // instruction may still be present. In this case, we should
+        // return immediately without optimization.
+        return 0;
+    }
     // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must*
     // make progress in order to avoid infinite loops or excessively-long
     // side-exit chains. We can only insert the executor into the bytecode if

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to