diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 725e07f3ad023f..ec65ed49281527 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -4,7 +4,7 @@ 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 @@ def test_no_memory(self): 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 index 00000000000000..b2484bf7c01a72 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst @@ -0,0 +1 @@ +Fix crash when calling :meth:`!list.append` as an unbound method. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a6cdc089d7a851..d17cac2473b101 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -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); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index c0422d87bfd78b..497aa909b329c1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5710,7 +5710,10 @@ 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(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4a3884b9568b98..fa3de197f4bcab 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3265,7 +3265,11 @@ 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));