From 3f4db453c2f65807f51da33d65702a7d4290cd44 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 17:47:46 +0300 Subject: [PATCH 1/5] gh-132011: Fix crash on invalid `CALL_LIST_APPEND` deoptimization --- 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 725e07f3ad023f..e35f9f9d4b0efa 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` specializetion 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: + assert False + """) + + 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..d6f5260a5e4de7 --- /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 on incorrect ``CALL_LIST_APPEND`` deoptimization. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8d7e137c82943a..9f4337353f9bc8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4233,7 +4233,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 ca64d7557e33d5..d816ddbcf4334c 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5834,7 +5834,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 41ea054d3f5eea..a1698fd385318a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3342,7 +3342,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)); From cac64f15a3f3e989d9b3787cc1a7e6d914c5b4ad Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 18:01:46 +0300 Subject: [PATCH 2/5] Update Lib/test/test_list.py Co-authored-by: Victor Stinner --- Lib/test/test_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index e35f9f9d4b0efa..4647642af8752d 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -346,7 +346,7 @@ def lappend(l, x, y): except TypeError: pass else: - assert False + raise AssertionError """) rc, _, _ = assert_python_ok("-c", code) From 210772f387b581e1dd6547a35e8f75be6789f2bf Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 18:28:04 +0300 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Peter Bierma --- Lib/test/test_list.py | 2 +- .../2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 4647642af8752d..94a1af0093d741 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -334,7 +334,7 @@ def test_no_memory(self): def test_deopt_from_append_list(self): # gh-132011: it used to crash, because - # of `CALL_LIST_APPEND` specializetion failure. + # of `CALL_LIST_APPEND` specialization failure. code = textwrap.dedent(""" l = [] def lappend(l, x, y): 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 index d6f5260a5e4de7..c36cdd5dc10446 100644 --- 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 @@ -1 +1 @@ -Fix crash on incorrect ``CALL_LIST_APPEND`` deoptimization. +Fix crash when calling :meth:`list.append` as an unbound method. From f868359a05f07299abf8a8b2027f3a49413ad0de Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 18:41:21 +0300 Subject: [PATCH 4/5] Address review --- Lib/test/test_list.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 94a1af0093d741..ec65ed49281527 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -336,17 +336,17 @@ 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 + 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) From 0b94d0c141dd79a3f537769373697539cdfe22ba Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 19:08:01 +0300 Subject: [PATCH 5/5] Update Misc/NEWS.d/next/Core_and_Builtins/2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst Co-authored-by: Peter Bierma --- .../2025-04-02-17-47-14.gh-issue-132011.dNh64H.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index c36cdd5dc10446..b2484bf7c01a72 100644 --- 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 @@ -1 +1 @@ -Fix crash when calling :meth:`list.append` as an unbound method. +Fix crash when calling :meth:`!list.append` as an unbound method.