[Python] Fix memory leak.

SWIG python objects were being freed after the corresponding SWIG
module information was destroyed in Python 3, causing leaks when as
a result the object destructor could not be invoked. To prevent this
misordering, SWIG python objects now obtain a reference to the
Python capsule wrapping the module information, so that the module
information is correctly destroyed after all SWIG python objects
have been freed (and corresponding destructors invoked).

Fixes #2154
Fixes #2208
This commit is contained in:
Olly Betts 2022-03-07 14:29:17 +13:00
commit e5996be10c
2 changed files with 22 additions and 2 deletions

View file

@ -719,6 +719,8 @@ SwigPyObject_Check(PyObject *op) {
SWIGRUNTIME PyObject *
SwigPyObject_New(void *ptr, swig_type_info *ty, int own);
static PyObject* Swig_Capsule_global = NULL;
SWIGRUNTIME void
SwigPyObject_dealloc(PyObject *v)
{
@ -769,7 +771,8 @@ SwigPyObject_dealloc(PyObject *v)
printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown"));
}
#endif
}
Py_XDECREF(Swig_Capsule_global);
}
Py_XDECREF(next);
#ifdef SWIGPYTHON_BUILTIN
Py_XDECREF(sobj->dict);
@ -994,6 +997,9 @@ SwigPyObject_New(void *ptr, swig_type_info *ty, int own)
#ifdef SWIGPYTHON_BUILTIN
sobj->dict = 0;
#endif
if (own == SWIG_POINTER_OWN) {
Py_XINCREF(Swig_Capsule_global);
}
}
return (PyObject *)sobj;
}
@ -1663,6 +1669,7 @@ SWIG_Python_DestroyModule(PyObject *obj)
Swig_Globals_global = NULL;
Py_DECREF(SWIG_Python_TypeCache());
Swig_TypeCache_global = NULL;
Swig_Capsule_global = NULL;
}
SWIGRUNTIME void
@ -1676,7 +1683,9 @@ SWIG_Python_SetModule(swig_module_info *swig_module) {
#endif
PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule);
if (pointer && module) {
if (PyModule_AddObject(module, "type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer) != 0) {
if (PyModule_AddObject(module, "type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer) == 0) {
Swig_Capsule_global = pointer;
} else {
Py_DECREF(pointer);
}
} else {