diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index f9e12931a63e4f..d80d317aab1ddc 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -4,6 +4,7 @@ run_with_locale, cpython_only, no_rerun, MISSING_C_DOCSTRINGS, EqualToForwardRef, ) +from test.support.script_helper import assert_python_ok from test.support.import_helper import import_fresh_module import collections.abc @@ -672,6 +673,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 d17cac2473b101..53da324ee5ab89 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4300,12 +4300,14 @@ dummy_func( arguments--; total_args++; } + EXIT_IF(total_args == 0); PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); PyMethodDef *meth = method->d_method; EXIT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)); PyTypeObject *d_type = method->d_common.d_type; PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + assert(self != NULL); EXIT_IF(!Py_IS_TYPE(self, d_type)); STAT_INC(CALL, hit); int nargs = total_args - 1; @@ -4378,12 +4380,14 @@ dummy_func( arguments--; total_args++; } + EXIT_IF(total_args == 0); PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; /* Builtin METH_FASTCALL methods, without keywords */ EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); PyMethodDef *meth = method->d_method; EXIT_IF(meth->ml_flags != METH_FASTCALL); PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + assert(self != NULL); EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); STAT_INC(CALL, hit); int nargs = total_args - 1; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 497aa909b329c1..3457ff0d6a1c06 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5838,6 +5838,10 @@ arguments--; total_args++; } + if (total_args == 0) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); @@ -5850,6 +5854,7 @@ } PyTypeObject *d_type = method->d_common.d_type; PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + assert(self != NULL); if (!Py_IS_TYPE(self, d_type)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -5990,6 +5995,10 @@ arguments--; total_args++; } + if (total_args == 0) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); @@ -6001,6 +6010,7 @@ JUMP_TO_JUMP_TARGET(); } PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[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 fa3de197f4bcab..fb4ab92c635d9e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3333,6 +3333,11 @@ arguments--; total_args++; } + if (total_args == 0) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UPDATE_MISS_STATS(CALL); @@ -3346,6 +3351,7 @@ JUMP_TO_PREDICTED(CALL); } PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + assert(self != NULL); if (!Py_IS_TYPE(self, method->d_common.d_type)) { UPDATE_MISS_STATS(CALL); assert(_PyOpcode_Deopt[opcode] == (CALL)); @@ -3453,6 +3459,11 @@ arguments--; total_args++; } + if (total_args == 0) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UPDATE_MISS_STATS(CALL); @@ -3467,6 +3478,7 @@ } PyTypeObject *d_type = method->d_common.d_type; PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + assert(self != NULL); if (!Py_IS_TYPE(self, d_type)) { UPDATE_MISS_STATS(CALL); assert(_PyOpcode_Deopt[opcode] == (CALL));
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: