diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 9b2a5728e9f534..7c731b8b82d4e7 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -5,6 +5,8 @@ MISSING_C_DOCSTRINGS, ) from test.test_import import no_rerun +from test.support.script_helper import assert_python_ok + import collections.abc from collections import namedtuple import copy @@ -643,6 +645,24 @@ def test_traceback_and_frame_types(self): self.assertIsInstance(exc.__traceback__, types.TracebackType) self.assertIsInstance(exc.__traceback__.tb_frame, types.FrameType) + 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 6ee3bda6f703bf..7b488efd6971a1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3108,6 +3108,7 @@ dummy_func( args--; total_args++; } + DEOPT_IF(total_args == 0, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); @@ -3115,6 +3116,7 @@ dummy_func( DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); PyTypeObject *d_type = callable->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; @@ -3173,6 +3175,7 @@ dummy_func( args--; total_args++; } + DEOPT_IF(total_args == 0, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); /* Builtin METH_FASTCALL methods, without keywords */ @@ -3180,6 +3183,7 @@ dummy_func( PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 246d37e771e3c3..53e6c1f81955ba 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4300,6 +4300,7 @@ args--; total_args++; } + DEOPT_IF(total_args == 0, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); @@ -4307,6 +4308,7 @@ DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); PyTypeObject *d_type = callable->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; @@ -4322,7 +4324,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4326 "Python/generated_cases.c.h" + #line 4328 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4335,7 +4337,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3137 "Python/bytecodes.c" + #line 3139 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4364,7 +4366,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4368 "Python/generated_cases.c.h" + #line 4370 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4377,7 +4379,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3169 "Python/bytecodes.c" + #line 3171 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4385,6 +4387,7 @@ args--; total_args++; } + DEOPT_IF(total_args == 0, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); /* Builtin METH_FASTCALL methods, without keywords */ @@ -4392,6 +4395,7 @@ PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; + assert(self != NULL); DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = @@ -4405,7 +4409,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4409 "Python/generated_cases.c.h" + #line 4413 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4415,9 +4419,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3200 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4421 "Python/generated_cases.c.h" + #line 4425 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4426,7 +4430,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3204 "Python/bytecodes.c" + #line 3208 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4488,14 +4492,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4492 "Python/generated_cases.c.h" + #line 4496 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3266 "Python/bytecodes.c" + #line 3270 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4499 "Python/generated_cases.c.h" + #line 4503 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4510,7 +4514,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3276 "Python/bytecodes.c" + #line 3280 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4539,14 +4543,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4543 "Python/generated_cases.c.h" + #line 4547 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3307 "Python/bytecodes.c" + #line 3311 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4567,7 +4571,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4571 "Python/generated_cases.c.h" + #line 4575 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4575,15 +4579,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3330 "Python/bytecodes.c" + #line 3334 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4581 "Python/generated_cases.c.h" + #line 4585 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3332 "Python/bytecodes.c" + #line 3336 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4587 "Python/generated_cases.c.h" + #line 4591 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4594,7 +4598,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3336 "Python/bytecodes.c" + #line 3340 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4629,7 +4633,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4633 "Python/generated_cases.c.h" + #line 4637 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4638,10 +4642,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3373 "Python/bytecodes.c" + #line 3377 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4645 "Python/generated_cases.c.h" + #line 4649 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4653,7 +4657,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3378 "Python/bytecodes.c" + #line 3382 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4668,12 +4672,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4672 "Python/generated_cases.c.h" + #line 4676 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3393 "Python/bytecodes.c" + #line 3397 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4677 "Python/generated_cases.c.h" + #line 4681 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4683,16 +4687,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3398 "Python/bytecodes.c" + #line 3402 "Python/bytecodes.c" assert(oparg >= 2); - #line 4689 "Python/generated_cases.c.h" + #line 4693 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3402 "Python/bytecodes.c" + #line 3406 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4704,26 +4708,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4708 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3416 "Python/bytecodes.c" + #line 3420 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4714 "Python/generated_cases.c.h" + #line 4718 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3420 "Python/bytecodes.c" + #line 3424 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4721 "Python/generated_cases.c.h" + #line 4725 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3425 "Python/bytecodes.c" + #line 3429 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4732,12 +4736,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4736 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3436 "Python/bytecodes.c" + #line 3440 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4746,12 +4750,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4750 "Python/generated_cases.c.h" + #line 4754 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3447 "Python/bytecodes.c" + #line 3451 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4763,12 +4767,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4767 "Python/generated_cases.c.h" + #line 4771 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3461 "Python/bytecodes.c" + #line 3465 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4780,30 +4784,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4784 "Python/generated_cases.c.h" + #line 4788 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3475 "Python/bytecodes.c" + #line 3479 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4795 "Python/generated_cases.c.h" + #line 4799 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3483 "Python/bytecodes.c" + #line 3487 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4802 "Python/generated_cases.c.h" + #line 4806 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3488 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4809 "Python/generated_cases.c.h" + #line 4813 "Python/generated_cases.c.h" }