mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-117142: Slightly hacky fix for memory leak of StgInfo (GH-119424)
Add a funciton that inlines PyObject_GetTypeData and skips type-checking, so it doesn't need access to the CType_Type object. This will break if the memory layout changes, but should be an acceptable solution to enable ctypes in subinterpreters in Python 3.13. Mark _ctypes as safe for multiple interpreters Co-authored-by: neonene <53406459+neonene@users.noreply.github.com>
This commit is contained in:
parent
406ffb5293
commit
a192547dfe
2 changed files with 45 additions and 53 deletions
|
@ -454,10 +454,8 @@ class _ctypes.CType_Type "PyObject *" "clinic_state()->CType_Type"
|
||||||
static int
|
static int
|
||||||
CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
|
CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
|
StgInfo *info = _PyStgInfo_FromType_NoState(self);
|
||||||
if (st && st->PyCType_Type) {
|
if (!info) {
|
||||||
StgInfo *info;
|
|
||||||
if (PyStgInfo_FromType(st, self, &info) < 0) {
|
|
||||||
PyErr_WriteUnraisable(self);
|
PyErr_WriteUnraisable(self);
|
||||||
}
|
}
|
||||||
if (info) {
|
if (info) {
|
||||||
|
@ -468,7 +466,6 @@ CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
Py_VISIT(info->checker);
|
Py_VISIT(info->checker);
|
||||||
Py_VISIT(info->module);
|
Py_VISIT(info->module);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Py_VISIT(Py_TYPE(self));
|
Py_VISIT(Py_TYPE(self));
|
||||||
return PyType_Type.tp_traverse(self, visit, arg);
|
return PyType_Type.tp_traverse(self, visit, arg);
|
||||||
}
|
}
|
||||||
|
@ -488,26 +485,21 @@ ctype_clear_stginfo(StgInfo *info)
|
||||||
static int
|
static int
|
||||||
CType_Type_clear(PyObject *self)
|
CType_Type_clear(PyObject *self)
|
||||||
{
|
{
|
||||||
ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
|
StgInfo *info = _PyStgInfo_FromType_NoState(self);
|
||||||
if (st && st->PyCType_Type) {
|
if (!info) {
|
||||||
StgInfo *info;
|
|
||||||
if (PyStgInfo_FromType(st, self, &info) < 0) {
|
|
||||||
PyErr_WriteUnraisable(self);
|
PyErr_WriteUnraisable(self);
|
||||||
}
|
}
|
||||||
if (info) {
|
if (info) {
|
||||||
ctype_clear_stginfo(info);
|
ctype_clear_stginfo(info);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return PyType_Type.tp_clear(self);
|
return PyType_Type.tp_clear(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CType_Type_dealloc(PyObject *self)
|
CType_Type_dealloc(PyObject *self)
|
||||||
{
|
{
|
||||||
ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
|
StgInfo *info = _PyStgInfo_FromType_NoState(self);
|
||||||
if (st && st->PyCType_Type) {
|
if (!info) {
|
||||||
StgInfo *info;
|
|
||||||
if (PyStgInfo_FromType(st, self, &info) < 0) {
|
|
||||||
PyErr_WriteUnraisable(self);
|
PyErr_WriteUnraisable(self);
|
||||||
}
|
}
|
||||||
if (info) {
|
if (info) {
|
||||||
|
@ -519,7 +511,7 @@ CType_Type_dealloc(PyObject *self)
|
||||||
info->shape = NULL;
|
info->shape = NULL;
|
||||||
ctype_clear_stginfo(info);
|
ctype_clear_stginfo(info);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PyTypeObject *tp = Py_TYPE(self);
|
PyTypeObject *tp = Py_TYPE(self);
|
||||||
PyType_Type.tp_dealloc(self);
|
PyType_Type.tp_dealloc(self);
|
||||||
Py_DECREF(tp);
|
Py_DECREF(tp);
|
||||||
|
@ -5947,7 +5939,7 @@ module_free(void *module)
|
||||||
|
|
||||||
static PyModuleDef_Slot module_slots[] = {
|
static PyModuleDef_Slot module_slots[] = {
|
||||||
{Py_mod_exec, _ctypes_mod_exec},
|
{Py_mod_exec, _ctypes_mod_exec},
|
||||||
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
|
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED},
|
||||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,20 +101,6 @@ get_module_state_by_def(PyTypeObject *cls)
|
||||||
return get_module_state(mod);
|
return get_module_state(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ctypes_state *
|
|
||||||
get_module_state_by_def_final(PyTypeObject *cls)
|
|
||||||
{
|
|
||||||
if (cls->tp_mro == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
PyObject *mod = PyType_GetModuleByDef(cls, &_ctypesmodule);
|
|
||||||
if (mod == NULL) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return get_module_state(mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern PyType_Spec carg_spec;
|
extern PyType_Spec carg_spec;
|
||||||
extern PyType_Spec cfield_spec;
|
extern PyType_Spec cfield_spec;
|
||||||
|
@ -502,6 +488,20 @@ PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result)
|
||||||
return _stginfo_from_type(state, Py_TYPE(obj), result);
|
return _stginfo_from_type(state, Py_TYPE(obj), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A variant of PyStgInfo_FromType that doesn't need the state,
|
||||||
|
* so it can be called from finalization functions when the module
|
||||||
|
* state is torn down. Does no checks; cannot fail.
|
||||||
|
* This inlines the current implementation PyObject_GetTypeData,
|
||||||
|
* so it might break in the future.
|
||||||
|
*/
|
||||||
|
static inline StgInfo *
|
||||||
|
_PyStgInfo_FromType_NoState(PyObject *type)
|
||||||
|
{
|
||||||
|
size_t type_basicsize =_Py_SIZE_ROUND_UP(PyType_Type.tp_basicsize,
|
||||||
|
ALIGNOF_MAX_ALIGN_T);
|
||||||
|
return (StgInfo *)((char *)type + type_basicsize);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize StgInfo on a newly created type
|
// Initialize StgInfo on a newly created type
|
||||||
static inline StgInfo *
|
static inline StgInfo *
|
||||||
PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)
|
PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue