]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-143026: Fix assertion error in executor management. (GH-143104)
authorMark Shannon <mark@hotpy.org>
Tue, 23 Dec 2025 17:19:34 +0000 (17:19 +0000)
committerGitHub <noreply@github.com>
Tue, 23 Dec 2025 17:19:34 +0000 (17:19 +0000)
Include/internal/pycore_object.h
Include/internal/pycore_optimizer.h
Lib/test/test_capi/test_opt.py
Python/optimizer.c
Tools/cases_generator/analyzer.py

index 6b91e4334b169eead3538d95aae29a60fb175de0..d14cee6af66103d5cfd080ed86760006ba6a3542 100644 (file)
@@ -252,25 +252,6 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
     }
 }
 
-static inline void
-_Py_DECREF_NO_DEALLOC(PyObject *op)
-{
-    if (_Py_IsImmortal(op)) {
-        _Py_DECREF_IMMORTAL_STAT_INC();
-        return;
-    }
-    _Py_DECREF_STAT_INC();
-#ifdef Py_REF_DEBUG
-    _Py_DEC_REFTOTAL(PyInterpreterState_Get());
-#endif
-    op->ob_refcnt--;
-#ifdef Py_DEBUG
-    if (op->ob_refcnt <= 0) {
-        _Py_FatalRefcountError("Expected a positive remaining refcount");
-    }
-#endif
-}
-
 #else
 // TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build
 static inline void
@@ -279,12 +260,6 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
     Py_DECREF(op);
 }
 
-static inline void
-_Py_DECREF_NO_DEALLOC(PyObject *op)
-{
-    Py_DECREF(op);
-}
-
 static inline int
 _Py_REF_IS_MERGED(Py_ssize_t ob_ref_shared)
 {
index 3ee62f1728321d38abcede06b5cad47dfad584b3..6a0fc1a59e7965367b744f2b029c61a5b4257588 100644 (file)
@@ -27,6 +27,7 @@ typedef struct {
     uint8_t valid;
     uint8_t chain_depth;  // Must be big enough for MAX_CHAIN_DEPTH - 1.
     bool warm;
+    uint8_t pending_deletion;
     int32_t index;           // Index of ENTER_EXECUTOR (if code isn't NULL, below).
     _PyBloomFilter bloom;
     _PyExecutorLinkListNode links;
index 3d2b61d355a309e62f39435bef0b671e0996b94a..16288a447e20febcb9fc4b3c1725916fd062fa33 100644 (file)
@@ -3114,6 +3114,26 @@ class TestUopsOptimization(unittest.TestCase):
         self.assertNotIn("_POP_TOP_INT", uops)
         self.assertIn("_POP_TOP_NOP", uops)
 
+    def test_143026(self):
+        # https://github.com/python/cpython/issues/143026
+
+        result = script_helper.run_python_until_end('-c', textwrap.dedent("""
+        import gc
+        thresholds = gc.get_threshold()
+        try:
+            gc.set_threshold(1)
+
+            def f1():
+                for i in range(5000):
+                    globals()[''] = i
+
+            f1()
+        finally:
+            gc.set_threshold(*thresholds)
+        """), PYTHON_JIT="1")
+        self.assertEqual(result[0].rc, 0, result)
+
+
 def global_identity(x):
     return x
 
index 869889bf2598d8a11b7d97fd8c296006e59e7ce7..0f8ddb4ba558d345c6ba7685d2b4896cdb26c6fe 100644 (file)
@@ -310,7 +310,7 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
     while (ts) {
         _PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor;
         if (current != NULL) {
-            _Py_DECREF_NO_DEALLOC((PyObject *)current);
+            Py_DECREF((PyObject *)current);
         }
         ts = ts->next;
     }
@@ -320,6 +320,10 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
 static void
 add_to_pending_deletion_list(_PyExecutorObject *self)
 {
+    if (self->vm_data.pending_deletion) {
+        return;
+    }
+    self->vm_data.pending_deletion = 1;
     PyInterpreterState *interp = PyInterpreterState_Get();
     self->vm_data.links.previous = NULL;
     self->vm_data.links.next = interp->executor_deletion_list_head;
@@ -627,7 +631,7 @@ _PyJit_translate_single_bytecode_to_trace(
     uint32_t target = 0;
 
     target = Py_IsNone((PyObject *)old_code)
-        ? (int)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR)
+        ? (uint32_t)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR)
         : INSTR_IP(target_instr, old_code);
 
     // Rewind EXTENDED_ARG so that we see the whole thing.
@@ -1666,6 +1670,7 @@ void
 _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_set)
 {
     executor->vm_data.valid = true;
+    executor->vm_data.pending_deletion = 0;
     for (int i = 0; i < _Py_BLOOM_FILTER_WORDS; i++) {
         executor->vm_data.bloom.bits[i] = dependency_set->bits[i];
     }
index 659befe312afaf181465382c8e121a5ad4724197..2001fb7c37931abfef87c45348a1957bb7081772 100644 (file)
@@ -673,7 +673,6 @@ NON_ESCAPING_FUNCTIONS = (
     "_PyUnicode_Equal",
     "_PyUnicode_JoinArray",
     "_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY",
-    "_Py_DECREF_NO_DEALLOC",
     "_Py_ID",
     "_Py_IsImmortal",
     "_Py_IsOwnedByCurrentThread",