https://github.com/python/cpython/commit/5911768600f6e7ff16043f9402416f0adf035b02 commit: 5911768600f6e7ff16043f9402416f0adf035b02 branch: 3.13 author: Peter Bierma <zintensity...@gmail.com> committer: Yhg1s <tho...@python.org> date: 2025-04-08T11:02:29Z summary:
[3.13] gh-131998: Fix `NULL` dereference when using an unbound method descriptor in a specialized code path (GH-132000) (#132262) (cherry picked from commit ac3c439cdfee8452f2bcceacd67a1f4e423ac3cf) Co-authored-by: Peter Bierma <zintensity...@gmail.com> Co-authored-by: sobolevn <m...@sobolevn.me> Co-authored-by: Victor Stinner <vstin...@python.org> Co-authored-by: Mark Shannon <m...@hotpy.org> files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-01-22-24-19.gh-issue-131998.DvmZcT.rst M Lib/test/test_types.py M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 128b1ae05e91cc..5e870e5545e48c 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -6,6 +6,9 @@ MISSING_C_DOCSTRINGS, ) from test.test_import import no_rerun +from test.support.script_helper import assert_python_ok +from test.support.import_helper import import_fresh_module + import collections.abc from collections import namedtuple, UserDict import copy @@ -648,6 +651,24 @@ def test_traceback_and_frame_types(self): def test_capsule_type(self): self.assertIsInstance(_datetime.datetime_CAPI, types.CapsuleType) + def test_call_unbound_crash(self): + # GH-131998: The specialized instruction would get tricked into dereferencing + # a bound "self" that didn't exist if subsequently called unbound. + code = """if True: + + def call(part): + [] + ([] + []) + part.pop() + + for _ in range(3): + call(['a']) + try: + call(list) + except TypeError: + pass + """ + assert_python_ok("-c", code) + class UnionTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-01-22-24-19.gh-issue-131998.DvmZcT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-01-22-24-19.gh-issue-131998.DvmZcT.rst new file mode 100644 index 00000000000000..e83004d925ad1e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-01-22-24-19.gh-issue-131998.DvmZcT.rst @@ -0,0 +1,2 @@ +Fix a crash when using an unbound method :term:`descriptor` object in a +function where a bound method descriptor was used. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ba8ecc7faf2dbc..6d5a42943b0d98 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3686,12 +3686,14 @@ dummy_func( args--; total_args++; } + DEOPT_IF(total_args == 0); PyMethodDescrObject *method = (PyMethodDescrObject *)callable; DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)); PyTypeObject *d_type = method->d_common.d_type; PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, d_type)); STAT_INC(CALL, hit); int nargs = total_args - 1; @@ -3754,11 +3756,13 @@ dummy_func( total_args++; } PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(total_args == 0); /* Builtin METH_FASTCALL methods, without keywords */ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL); PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); STAT_INC(CALL, hit); PyCFunctionFast cfunc = diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index df7c19a80e40c5..1bfbeb675b1b6f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3817,6 +3817,10 @@ args--; total_args++; } + if (total_args == 0) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } PyMethodDescrObject *method = (PyMethodDescrObject *)callable; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); @@ -3829,6 +3833,7 @@ } PyTypeObject *d_type = method->d_common.d_type; PyObject *self = args[0]; + assert(self != NULL); if (!Py_IS_TYPE(self, d_type)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -3918,6 +3923,10 @@ total_args++; } PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + if (total_args == 0) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } /* Builtin METH_FASTCALL methods, without keywords */ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); @@ -3929,6 +3938,7 @@ JUMP_TO_JUMP_TARGET(); } PyObject *self = args[0]; + assert(self != NULL); if (!Py_IS_TYPE(self, method->d_common.d_type)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 93d5a782b469d4..9665774cf9c03c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1627,11 +1627,13 @@ total_args++; } PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(total_args == 0, CALL); /* Builtin METH_FASTCALL methods, without keywords */ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunctionFast cfunc = @@ -1676,12 +1678,14 @@ args--; total_args++; } + DEOPT_IF(total_args == 0, CALL); PyMethodDescrObject *method = (PyMethodDescrObject *)callable; DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); PyTypeObject *d_type = method->d_common.d_type; PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); int nargs = total_args - 1; _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com