From c0661df42ad20e488dbfa3e0fec22462833fc3d6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 6 Apr 2025 19:10:39 +0300 Subject: [PATCH] gh-132011: Fix crash on invalid `CALL_LIST_APPEND` deoptimization (#132018) Co-authored-by: Victor Stinner Co-authored-by: Peter Bierma --- Lib/test/test_list.py | 22 ++++++++++++++++++- ...-04-02-17-47-14.gh-issue-132011.dNh64H.rst | 1 + Python/bytecodes.c | 2 +- Python/executor_cases.c.h | 5 ++++- Python/generated_cases.c.h | 6 ++++- 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 725e07f3ad0..ec65ed49281 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -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 index 00000000000..b2484bf7c01 --- /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 a6cdc089d7a..d17cac2473b 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 c0422d87bfd..497aa909b32 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 4a3884b9568..fa3de197f4b 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));