Skip to content

Commit da8199f

Browse files
authored
gh-123241: Don't modify ref count during visitation (GH-142232)
1 parent 0dd8311 commit da8199f

File tree

4 files changed

+41
-22
lines changed

4 files changed

+41
-22
lines changed

Include/internal/pycore_typeobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject
155155
// Precalculates count of non-unique slots and fills wrapperbase.name_count.
156156
extern int _PyType_InitSlotDefs(PyInterpreterState *interp);
157157

158+
// Like PyType_GetBaseByToken, but does not modify refcounts.
159+
// Cannot fail; arguments must be valid.
160+
PyAPI_FUNC(int)
161+
_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result);
162+
158163
#ifdef __cplusplus
159164
}
160165
#endif
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid reference count operations in garbage collection of :mod:`ctypes`
2+
objects.

Modules/_ctypes/ctypes.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -608,25 +608,21 @@ PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result)
608608
return _stginfo_from_type(state, Py_TYPE(obj), result);
609609
}
610610

611-
/* A variant of PyStgInfo_FromType that doesn't need the state,
611+
/* A variant of PyStgInfo_FromType that doesn't need the state
612+
* and doesn't modify any refcounts,
612613
* so it can be called from finalization functions when the module
613614
* state is torn down.
614615
*/
615616
static inline StgInfo *
616617
_PyStgInfo_FromType_NoState(PyObject *type)
617618
{
618619
PyTypeObject *PyCType_Type;
619-
if (PyType_GetBaseByToken(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0) {
620-
return NULL;
621-
}
622-
if (PyCType_Type == NULL) {
623-
PyErr_Format(PyExc_TypeError, "expected a ctypes type, got '%N'", type);
620+
if (_PyType_GetBaseByToken_Borrow(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0 ||
621+
PyCType_Type == NULL) {
624622
return NULL;
625623
}
626624

627-
StgInfo *info = PyObject_GetTypeData(type, PyCType_Type);
628-
Py_DECREF(PyCType_Type);
629-
return info;
625+
return PyObject_GetTypeData(type, PyCType_Type);
630626
}
631627

632628
// Initialize StgInfo on a newly created type

Objects/typeobject.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5877,23 +5877,15 @@ get_base_by_token_recursive(PyObject *bases, void *token)
58775877
}
58785878

58795879
int
5880-
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
5880+
_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result)
58815881
{
5882+
assert(token != NULL);
5883+
assert(PyType_Check(type));
5884+
58825885
if (result != NULL) {
58835886
*result = NULL;
58845887
}
58855888

5886-
if (token == NULL) {
5887-
PyErr_Format(PyExc_SystemError,
5888-
"PyType_GetBaseByToken called with token=NULL");
5889-
return -1;
5890-
}
5891-
if (!PyType_Check(type)) {
5892-
PyErr_Format(PyExc_TypeError,
5893-
"expected a type, got a '%T' object", type);
5894-
return -1;
5895-
}
5896-
58975889
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
58985890
// No static type has a heaptype superclass,
58995891
// which is ensured by type_ready_mro().
@@ -5902,7 +5894,7 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
59025894
if (((PyHeapTypeObject*)type)->ht_token == token) {
59035895
found:
59045896
if (result != NULL) {
5905-
*result = (PyTypeObject *)Py_NewRef(type);
5897+
*result = type;
59065898
}
59075899
return 1;
59085900
}
@@ -5936,6 +5928,30 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
59365928
return 0;
59375929
}
59385930

5931+
int
5932+
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
5933+
{
5934+
if (result != NULL) {
5935+
*result = NULL;
5936+
}
5937+
if (token == NULL) {
5938+
PyErr_Format(PyExc_SystemError,
5939+
"PyType_GetBaseByToken called with token=NULL");
5940+
return -1;
5941+
}
5942+
if (!PyType_Check(type)) {
5943+
PyErr_Format(PyExc_TypeError,
5944+
"expected a type, got a '%T' object", type);
5945+
return -1;
5946+
}
5947+
5948+
int res = _PyType_GetBaseByToken_Borrow(type, token, result);
5949+
if (res > 0 && result) {
5950+
Py_INCREF(*result);
5951+
}
5952+
return res;
5953+
}
5954+
59395955

59405956
void *
59415957
PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls)

0 commit comments

Comments
 (0)