https://github.com/python/cpython/commit/e09c4deb254a85ef2be7a0a636c2845688c915ad commit: e09c4deb254a85ef2be7a0a636c2845688c915ad branch: 3.14 author: Petr Viktorin <[email protected]> committer: DinoV <[email protected]> date: 2025-12-11T10:51:11-08:00 summary:
[3.14] gh-123241: Don't modify ref count during visitation (GH-142232) (#142567) (cherry picked from commit da8199f8842c2830fa4015138725849863523de4) Co-authored-by: Dino Viehland <[email protected]> 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 1a4f89fd2449a0..ba66364d3e94b1 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -149,6 +149,11 @@ typedef int (*_py_validate_type)(PyTypeObject *); extern int _PyType_Validate(PyTypeObject *ty, _py_validate_type validate, unsigned int *tp_version); extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version); +// 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 f8389f98fec780..78a33fea0192c2 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -596,7 +596,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. */ @@ -604,17 +605,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 05d12bf6bbaf5c..adbc0743161326 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5533,23 +5533,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(). @@ -5558,7 +5550,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; } @@ -5592,6 +5584,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]
