[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

@ -154,6 +154,17 @@ Version 4.1.0 (in progress)
things like `%std::vector<std::string>` now give an error rather
than being quietly ignored.
2022-02-11: adr26
[Python] #2154 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).
2022-02-10: olly
[Tcl] https://sourceforge.net/p/swig/bugs/1207/
https://sourceforge.net/p/swig/bugs/1213/

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 {