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]