summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-05-30 09:24:42 (GMT)
committerGitHub <noreply@github.com>2024-05-30 09:24:42 (GMT)
commit322e0ad3dec0068224657ea550ddbaac96d44648 (patch)
treec19eadea119f824ccc2de73413e9cad78df1bcc6 /Modules
parentd1c7f5ed08a7f92afeb760c32e33d6d49dd1ad5b (diff)
downloadcpython-322e0ad3dec0068224657ea550ddbaac96d44648.zip
cpython-322e0ad3dec0068224657ea550ddbaac96d44648.tar.gz
cpython-322e0ad3dec0068224657ea550ddbaac96d44648.tar.bz2
[3.13] gh-117142: Slightly hacky fix for memory leak of StgInfo (GH-119424) (GH-119468)
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 (cherry picked from commit a192547dfe7c4f184cc8b579c3eff2f61f642483) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: neonene <53406459+neonene@users.noreply.github.com>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ctypes/_ctypes.c70
-rw-r--r--Modules/_ctypes/ctypes.h28
2 files changed, 45 insertions, 53 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 574cb80..6c1e5f5 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -454,20 +454,17 @@ class _ctypes.CType_Type "PyObject *" "clinic_state()->CType_Type"
static int
CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
{
- ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
- if (st && st->PyCType_Type) {
- StgInfo *info;
- if (PyStgInfo_FromType(st, self, &info) < 0) {
- PyErr_WriteUnraisable(self);
- }
- if (info) {
- Py_VISIT(info->proto);
- Py_VISIT(info->argtypes);
- Py_VISIT(info->converters);
- Py_VISIT(info->restype);
- Py_VISIT(info->checker);
- Py_VISIT(info->module);
- }
+ StgInfo *info = _PyStgInfo_FromType_NoState(self);
+ if (!info) {
+ PyErr_WriteUnraisable(self);
+ }
+ if (info) {
+ Py_VISIT(info->proto);
+ Py_VISIT(info->argtypes);
+ Py_VISIT(info->converters);
+ Py_VISIT(info->restype);
+ Py_VISIT(info->checker);
+ Py_VISIT(info->module);
}
Py_VISIT(Py_TYPE(self));
return PyType_Type.tp_traverse(self, visit, arg);
@@ -488,15 +485,12 @@ ctype_clear_stginfo(StgInfo *info)
static int
CType_Type_clear(PyObject *self)
{
- ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
- if (st && st->PyCType_Type) {
- StgInfo *info;
- if (PyStgInfo_FromType(st, self, &info) < 0) {
- PyErr_WriteUnraisable(self);
- }
- if (info) {
- ctype_clear_stginfo(info);
- }
+ StgInfo *info = _PyStgInfo_FromType_NoState(self);
+ if (!info) {
+ PyErr_WriteUnraisable(self);
+ }
+ if (info) {
+ ctype_clear_stginfo(info);
}
return PyType_Type.tp_clear(self);
}
@@ -504,22 +498,20 @@ CType_Type_clear(PyObject *self)
static void
CType_Type_dealloc(PyObject *self)
{
- ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
- if (st && st->PyCType_Type) {
- StgInfo *info;
- if (PyStgInfo_FromType(st, self, &info) < 0) {
- PyErr_WriteUnraisable(self);
- }
- if (info) {
- PyMem_Free(info->ffi_type_pointer.elements);
- info->ffi_type_pointer.elements = NULL;
- PyMem_Free(info->format);
- info->format = NULL;
- PyMem_Free(info->shape);
- info->shape = NULL;
- ctype_clear_stginfo(info);
- }
+ StgInfo *info = _PyStgInfo_FromType_NoState(self);
+ if (!info) {
+ PyErr_WriteUnraisable(self);
+ }
+ if (info) {
+ PyMem_Free(info->ffi_type_pointer.elements);
+ info->ffi_type_pointer.elements = NULL;
+ PyMem_Free(info->format);
+ info->format = NULL;
+ PyMem_Free(info->shape);
+ info->shape = NULL;
+ ctype_clear_stginfo(info);
}
+
PyTypeObject *tp = Py_TYPE(self);
PyType_Type.tp_dealloc(self);
Py_DECREF(tp);
@@ -5947,7 +5939,7 @@ module_free(void *module)
static PyModuleDef_Slot module_slots[] = {
{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},
{0, NULL}
};
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 20c6813..d46675a 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -101,20 +101,6 @@ get_module_state_by_def(PyTypeObject *cls)
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 cfield_spec;
@@ -508,6 +494,20 @@ 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,
+ * 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
static inline StgInfo *
PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)