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

Reply via email to