Skip to content

Commit e09c4de

Browse files
encukouDinoV
andauthored
[3.14] gh-123241: Don't modify ref count during visitation (GH-142232) (#142567)
(cherry picked from commit da8199f) Co-authored-by: Dino Viehland <[email protected]>
1 parent 65d07f1 commit e09c4de

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
@@ -149,6 +149,11 @@ typedef int (*_py_validate_type)(PyTypeObject *);
149149
extern int _PyType_Validate(PyTypeObject *ty, _py_validate_type validate, unsigned int *tp_version);
150150
extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version);
151151

152+
// Like PyType_GetBaseByToken, but does not modify refcounts.
153+
// Cannot fail; arguments must be valid.
154+
PyAPI_FUNC(int)
155+
_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result);
156+
152157
#ifdef __cplusplus
153158
}
154159
#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
@@ -596,25 +596,21 @@ PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result)
596596
return _stginfo_from_type(state, Py_TYPE(obj), result);
597597
}
598598

599-
/* A variant of PyStgInfo_FromType that doesn't need the state,
599+
/* A variant of PyStgInfo_FromType that doesn't need the state
600+
* and doesn't modify any refcounts,
600601
* so it can be called from finalization functions when the module
601602
* state is torn down.
602603
*/
603604
static inline StgInfo *
604605
_PyStgInfo_FromType_NoState(PyObject *type)
605606
{
606607
PyTypeObject *PyCType_Type;
607-
if (PyType_GetBaseByToken(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0) {
608-
return NULL;
609-
}
610-
if (PyCType_Type == NULL) {
611-
PyErr_Format(PyExc_TypeError, "expected a ctypes type, got '%N'", type);
608+
if (_PyType_GetBaseByToken_Borrow(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0 ||
609+
PyCType_Type == NULL) {
612610
return NULL;
613611
}
614612

615-
StgInfo *info = PyObject_GetTypeData(type, PyCType_Type);
616-
Py_DECREF(PyCType_Type);
617-
return info;
613+
return PyObject_GetTypeData(type, PyCType_Type);
618614
}
619615

620616
// Initialize StgInfo on a newly created type

Objects/typeobject.c

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

55355535
int
5536-
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
5536+
_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result)
55375537
{
5538+
assert(token != NULL);
5539+
assert(PyType_Check(type));
5540+
55385541
if (result != NULL) {
55395542
*result = NULL;
55405543
}
55415544

5542-
if (token == NULL) {
5543-
PyErr_Format(PyExc_SystemError,
5544-
"PyType_GetBaseByToken called with token=NULL");
5545-
return -1;
5546-
}
5547-
if (!PyType_Check(type)) {
5548-
PyErr_Format(PyExc_TypeError,
5549-
"expected a type, got a '%T' object", type);
5550-
return -1;
5551-
}
5552-
55535545
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
55545546
// No static type has a heaptype superclass,
55555547
// which is ensured by type_ready_mro().
@@ -5558,7 +5550,7 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
55585550
if (((PyHeapTypeObject*)type)->ht_token == token) {
55595551
found:
55605552
if (result != NULL) {
5561-
*result = (PyTypeObject *)Py_NewRef(type);
5553+
*result = type;
55625554
}
55635555
return 1;
55645556
}
@@ -5592,6 +5584,30 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
55925584
return 0;
55935585
}
55945586

5587+
int
5588+
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
5589+
{
5590+
if (result != NULL) {
5591+
*result = NULL;
5592+
}
5593+
if (token == NULL) {
5594+
PyErr_Format(PyExc_SystemError,
5595+
"PyType_GetBaseByToken called with token=NULL");
5596+
return -1;
5597+
}
5598+
if (!PyType_Check(type)) {
5599+
PyErr_Format(PyExc_TypeError,
5600+
"expected a type, got a '%T' object", type);
5601+
return -1;
5602+
}
5603+
5604+
int res = _PyType_GetBaseByToken_Borrow(type, token, result);
5605+
if (res > 0 && result) {
5606+
Py_INCREF(*result);
5607+
}
5608+
return res;
5609+
}
5610+
55955611

55965612
void *
55975613
PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls)

0 commit comments

Comments
 (0)