diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index ad7accf2099f43..005374f429399f 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -1,6 +1,8 @@ import sys +import textwrap from test import list_tests from test.support import cpython_only +from test.support.script_helper import assert_python_ok import pickle import unittest @@ -309,5 +311,25 @@ def test_tier2_invalidates_iterator(self): a.append(4) self.assertEqual(list(it), []) + 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 1e6185d3c9e489..ba8ecc7faf2dbc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3631,7 +3631,7 @@ dummy_func( assert(oparg == 1); PyInterpreterState *interp = tstate->interp; DEOPT_IF(callable != interp->callable_cache.list_append); - assert(self != NULL); + DEOPT_IF(self == NULL); DEOPT_IF(!PyList_Check(self)); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, arg) < 0) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1488e4215cf579..93d5a782b469d4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1590,7 +1590,7 @@ assert(oparg == 1); PyInterpreterState *interp = tstate->interp; DEOPT_IF(callable != interp->callable_cache.list_append, CALL); - assert(self != NULL); + DEOPT_IF(self == NULL, CALL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, arg) < 0) {