https://github.com/python/cpython/commit/ac3c439cdfee8452f2bcceacd67a1f4e423ac3cf
commit: ac3c439cdfee8452f2bcceacd67a1f4e423ac3cf
branch: main
author: Peter Bierma <zintensity...@gmail.com>
committer: Yhg1s <tho...@python.org>
date: 2025-04-08T10:31:43Z
summary:

gh-131998: Fix `NULL` dereference when using an unbound method descriptor in a 
specialized code path (#132000)

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 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));

_______________________________________________
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

Reply via email to