]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132011: Fix crash on invalid `CALL_LIST_APPEND` deoptimization (#132018)
authorsobolevn <mail@sobolevn.me>
Sun, 6 Apr 2025 16:10:39 +0000 (19:10 +0300)
committerGitHub <noreply@github.com>
Sun, 6 Apr 2025 16:10:39 +0000 (19:10 +0300)
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Lib/test/test_list.py
Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst [new file with mode: 0644]
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h

index 725e07f3ad023fd98dafe38b7c0da9c18ee77eee..ec65ed49281527a35e63b0232b0ae3c579bbf69b 100644 (file)
@@ -4,7 +4,7 @@ import textwrap
 from test import list_tests, support
 from test.support import cpython_only
 from test.support.import_helper import import_module
-from test.support.script_helper import assert_python_failure
+from test.support.script_helper import assert_python_failure, assert_python_ok
 import pickle
 import unittest
 
@@ -332,5 +332,25 @@ class ListTest(list_tests.CommonTest):
         else:
             self.assertNotEqual(rc, -int(signal.SIGSEGV))
 
+    def test_deopt_from_append_list(self):
+        # gh-132011: it used to crash, because
+        # of `CALL_LIST_APPEND` specialization failure.
+        code = textwrap.dedent("""
+            l = []
+            def lappend(l, x, y):
+                l.append((x, y))
+            for x in range(3):
+                lappend(l, None, None)
+            try:
+                lappend(list, None, None)
+            except TypeError:
+                pass
+            else:
+                raise AssertionError
+        """)
+
+        rc, _, _ = assert_python_ok("-c", code)
+        self.assertEqual(rc, 0)
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst
new file mode 100644 (file)
index 0000000..b2484bf
--- /dev/null
@@ -0,0 +1 @@
+Fix crash when calling :meth:`!list.append` as an unbound method.
index a6cdc089d7a851bf7ea42e4f61604730d7148ef9..d17cac2473b10190221a5de9a43f55699e1463f7 100644 (file)
@@ -4235,7 +4235,7 @@ dummy_func(
 
             PyInterpreterState *interp = tstate->interp;
             DEOPT_IF(callable_o != interp->callable_cache.list_append);
-            assert(self_o != NULL);
+            DEOPT_IF(self_o == NULL);
             DEOPT_IF(!PyList_Check(self_o));
             DEOPT_IF(!LOCK_OBJECT(self_o));
             STAT_INC(CALL, hit);
index c0422d87bfd78b29a6c61ba84eb5b98c4ba480ba..497aa909b329c167d2bc10dcfe930bf267494bb9 100644 (file)
                 UOP_STAT_INC(uopcode, miss);
                 JUMP_TO_JUMP_TARGET();
             }
-            assert(self_o != NULL);
+            if (self_o == NULL) {
+                UOP_STAT_INC(uopcode, miss);
+                JUMP_TO_JUMP_TARGET();
+            }
             if (!PyList_Check(self_o)) {
                 UOP_STAT_INC(uopcode, miss);
                 JUMP_TO_JUMP_TARGET();
index 4a3884b9568b982b2e34441af99b801bb6a5f636..fa3de197f4bcab3780e58aee1178f74b6454d610 100644 (file)
                 assert(_PyOpcode_Deopt[opcode] == (CALL));
                 JUMP_TO_PREDICTED(CALL);
             }
-            assert(self_o != NULL);
+            if (self_o == NULL) {
+                UPDATE_MISS_STATS(CALL);
+                assert(_PyOpcode_Deopt[opcode] == (CALL));
+                JUMP_TO_PREDICTED(CALL);
+            }
             if (!PyList_Check(self_o)) {
                 UPDATE_MISS_STATS(CALL);
                 assert(_PyOpcode_Deopt[opcode] == (CALL));