https://github.com/python/cpython/commit/da8199f8842c2830fa4015138725849863523de4
commit: da8199f8842c2830fa4015138725849863523de4
branch: main
author: Dino Viehland <[email protected]>
committer: encukou <[email protected]>
date: 2025-12-11T09:54:29+01:00
summary:

gh-123241: Don't modify ref count during visitation (GH-142232)

files:
A Misc/NEWS.d/next/Library/2025-12-10-11-20-05.gh-issue-123241.oYg2n7.rst
M Include/internal/pycore_typeobject.h
M Modules/_ctypes/ctypes.h
M Objects/typeobject.c

diff --git a/Include/internal/pycore_typeobject.h 
b/Include/internal/pycore_typeobject.h
index 3661f171e2b013..abaa60890b55c8 100644
--- a/Include/internal/pycore_typeobject.h
+++ b/Include/internal/pycore_typeobject.h
@@ -155,6 +155,11 @@ extern int 
_PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject
 // Precalculates count of non-unique slots and fills wrapperbase.name_count.
 extern int _PyType_InitSlotDefs(PyInterpreterState *interp);
 
+// Like PyType_GetBaseByToken, but does not modify refcounts.
+// Cannot fail; arguments must be valid.
+PyAPI_FUNC(int)
+_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject 
**result);
+
 #ifdef __cplusplus
 }
 #endif
diff --git 
a/Misc/NEWS.d/next/Library/2025-12-10-11-20-05.gh-issue-123241.oYg2n7.rst 
b/Misc/NEWS.d/next/Library/2025-12-10-11-20-05.gh-issue-123241.oYg2n7.rst
new file mode 100644
index 00000000000000..871a03a6fd1021
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-10-11-20-05.gh-issue-123241.oYg2n7.rst
@@ -0,0 +1,2 @@
+Avoid reference count operations in garbage collection of :mod:`ctypes`
+objects.
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 9f995bf24080a5..478daecad55b94 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -608,7 +608,8 @@ PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, 
StgInfo **result)
     return _stginfo_from_type(state, Py_TYPE(obj), result);
 }
 
-/* A variant of PyStgInfo_FromType that doesn't need the state,
+/* A variant of PyStgInfo_FromType that doesn't need the state
+ * and doesn't modify any refcounts,
  * so it can be called from finalization functions when the module
  * state is torn down.
  */
@@ -616,17 +617,12 @@ static inline StgInfo *
 _PyStgInfo_FromType_NoState(PyObject *type)
 {
     PyTypeObject *PyCType_Type;
-    if (PyType_GetBaseByToken(Py_TYPE(type), &pyctype_type_spec, 
&PyCType_Type) < 0) {
-        return NULL;
-    }
-    if (PyCType_Type == NULL) {
-        PyErr_Format(PyExc_TypeError, "expected a ctypes type, got '%N'", 
type);
+    if (_PyType_GetBaseByToken_Borrow(Py_TYPE(type), &pyctype_type_spec, 
&PyCType_Type) < 0 ||
+        PyCType_Type == NULL) {
         return NULL;
     }
 
-    StgInfo *info = PyObject_GetTypeData(type, PyCType_Type);
-    Py_DECREF(PyCType_Type);
-    return info;
+    return PyObject_GetTypeData(type, PyCType_Type);
 }
 
 // Initialize StgInfo on a newly created type
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index cbe0215359e29d..7f5149aeece12b 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -5877,23 +5877,15 @@ get_base_by_token_recursive(PyObject *bases, void 
*token)
 }
 
 int
-PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
+_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject 
**result)
 {
+    assert(token != NULL);
+    assert(PyType_Check(type));
+
     if (result != NULL) {
         *result = NULL;
     }
 
-    if (token == NULL) {
-        PyErr_Format(PyExc_SystemError,
-                     "PyType_GetBaseByToken called with token=NULL");
-        return -1;
-    }
-    if (!PyType_Check(type)) {
-        PyErr_Format(PyExc_TypeError,
-                     "expected a type, got a '%T' object", type);
-        return -1;
-    }
-
     if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
         // No static type has a heaptype superclass,
         // which is ensured by type_ready_mro().
@@ -5902,7 +5894,7 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, 
PyTypeObject **result)
     if (((PyHeapTypeObject*)type)->ht_token == token) {
 found:
         if (result != NULL) {
-            *result = (PyTypeObject *)Py_NewRef(type);
+            *result = type;
         }
         return 1;
     }
@@ -5936,6 +5928,30 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, 
PyTypeObject **result)
     return 0;
 }
 
+int
+PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
+{
+    if (result != NULL) {
+         *result = NULL;
+    }
+    if (token == NULL) {
+        PyErr_Format(PyExc_SystemError,
+                     "PyType_GetBaseByToken called with token=NULL");
+        return -1;
+    }
+    if (!PyType_Check(type)) {
+        PyErr_Format(PyExc_TypeError,
+                     "expected a type, got a '%T' object", type);
+        return -1;
+    }
+
+    int res = _PyType_GetBaseByToken_Borrow(type, token, result);
+    if (res > 0 && result) {
+        Py_INCREF(*result);
+    }
+    return res;
+}
+
 
 void *
 PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls)

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to