[3.14] gh-123241: Don't modify ref count during visitation (GH-142232) (#142567)

(cherry picked from commit da8199f884)

Co-authored-by: Dino Viehland <dinoviehland@meta.com>
This commit is contained in:
Petr Viktorin 2025-12-11 19:51:11 +01:00 committed by GitHub
parent 65d07f1948
commit e09c4deb25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 22 deletions

View file

@ -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

View file

@ -0,0 +1,2 @@
Avoid reference count operations in garbage collection of :mod:`ctypes`
objects.

View file

@ -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

View file

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