Merge pull request #2019 from adr26/memleak

[Python] Fix memory leaks.
This commit is contained in:
William S Fulton 2021-05-20 20:55:39 +01:00 • committed by GitHub
commit e82725b22e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 132 additions and 55 deletions

View file

@ -7,6 +7,32 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress) Version 4.1.0 (in progress)
=========================== ===========================
2021-05-17: adr26
[Python] #1985 Fix memory leaks:
1. Python object references were being incorrectly retained by
SwigPyClientData, causing swig_varlink_dealloc() never to run / free
memory. SwigPyClientData_New() / SwigPyClientData_Del() were updated
to fix the object reference counting, causing swig_varlink_dealloc()
to run and the memory swig_varlink owns to be freed.
2. SwigPyClientData itself was not freed by SwigPyClientData_Del(),
causing another heap leak. The required free() was added to
SwigPyClientData_Del()
3. Fix reference counting/leak of python cached type query
4. Fix reference counting/leak of SwigPyObject dict (-builtin)
5. Python object reference counting fixes for out-of-memory
scenarios were added to: SWIG_Python_RaiseOrModifyTypeError(),
SWIG_Python_AppendOutput(), SwigPyClientData_New(),
SwigPyObject_get___dict__() and SwigPyObject_format()
6. Add error handling for PyModule_AddObject() to
SWIG_Python_SetModule() (failure could be caused by OOM or a name
clash caused by malicious code)
2021-05-13: olly 2021-05-13: olly
[UFFI] #2009 Remove code for Common Lisp UFFI. We dropped support [UFFI] #2009 Remove code for Common Lisp UFFI. We dropped support
for it in SWIG 4.0.0 and nobody has stepped forward to revive it in for it in SWIG 4.0.0 and nobody has stepped forward to revive it in

View file

@ -95,8 +95,12 @@ SWIG_Python_RaiseOrModifyTypeError(const char *message)
#else #else
newvalue = PyString_FromFormat("%s\nAdditional information:\n%s", PyString_AsString(value), message); newvalue = PyString_FromFormat("%s\nAdditional information:\n%s", PyString_AsString(value), message);
#endif #endif
Py_XDECREF(value); if (newvalue) {
PyErr_Restore(type, newvalue, traceback); Py_XDECREF(value);
PyErr_Restore(type, newvalue, traceback);
} else {
PyErr_Restore(type, value, traceback);
}
} else { } else {
/* Raise TypeError using given message */ /* Raise TypeError using given message */
PyErr_SetString(PyExc_TypeError, message); PyErr_SetString(PyExc_TypeError, message);

View file

@ -127,7 +127,12 @@ SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) {
if (!PyList_Check(result)) { if (!PyList_Check(result)) {
PyObject *o2 = result; PyObject *o2 = result;
result = PyList_New(1); result = PyList_New(1);
PyList_SetItem(result, 0, o2); if (result) {
PyList_SET_ITEM(result, 0, o2);
} else {
Py_DECREF(obj);
return o2;
}
} }
PyList_Append(result,obj); PyList_Append(result,obj);
Py_DECREF(obj); Py_DECREF(obj);
@ -279,18 +284,25 @@ SwigPyClientData_New(PyObject* obj)
/* the newraw method and newargs arguments used to create a new raw instance */ /* the newraw method and newargs arguments used to create a new raw instance */
if (PyClass_Check(obj)) { if (PyClass_Check(obj)) {
data->newraw = 0; data->newraw = 0;
data->newargs = obj;
Py_INCREF(obj); Py_INCREF(obj);
data->newargs = obj;
} else { } else {
data->newraw = PyObject_GetAttrString(data->klass, "__new__"); data->newraw = PyObject_GetAttrString(data->klass, "__new__");
if (data->newraw) { if (data->newraw) {
Py_INCREF(data->newraw); data->newargs = PyTuple_New(1);
data->newargs = PyTuple_New(1); if (data->newargs) {
PyTuple_SetItem(data->newargs, 0, obj); Py_INCREF(obj);
PyTuple_SET_ITEM(data->newargs, 0, obj);
} else {
Py_DECREF(data->newraw);
Py_DECREF(data->klass);
free(data);
return 0;
}
} else { } else {
data->newargs = obj; Py_INCREF(obj);
data->newargs = obj;
} }
Py_INCREF(data->newargs);
} }
/* the destroy method, aka as the C++ delete method */ /* the destroy method, aka as the C++ delete method */
data->destroy = PyObject_GetAttrString(data->klass, "__swig_destroy__"); data->destroy = PyObject_GetAttrString(data->klass, "__swig_destroy__");
@ -299,10 +311,7 @@ SwigPyClientData_New(PyObject* obj)
data->destroy = 0; data->destroy = 0;
} }
if (data->destroy) { if (data->destroy) {
int flags; data->delargs = !(PyCFunction_GET_FLAGS(data->destroy) & METH_O);
Py_INCREF(data->destroy);
flags = PyCFunction_GET_FLAGS(data->destroy);
data->delargs = !(flags & (METH_O));
} else { } else {
data->delargs = 0; data->delargs = 0;
} }
@ -313,10 +322,13 @@ SwigPyClientData_New(PyObject* obj)
} }
SWIGRUNTIME void SWIGRUNTIME void
SwigPyClientData_Del(SwigPyClientData *data) { SwigPyClientData_Del(SwigPyClientData *data)
{
Py_XDECREF(data->klass);
Py_XDECREF(data->newraw); Py_XDECREF(data->newraw);
Py_XDECREF(data->newargs); Py_XDECREF(data->newargs);
Py_XDECREF(data->destroy); Py_XDECREF(data->destroy);
free(data);
} }
/* =============== SwigPyObject =====================*/ /* =============== SwigPyObject =====================*/
@ -343,7 +355,7 @@ SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
if (!sobj->dict) if (!sobj->dict)
sobj->dict = PyDict_New(); sobj->dict = PyDict_New();
Py_INCREF(sobj->dict); Py_XINCREF(sobj->dict);
return sobj->dict; return sobj->dict;
} }
@ -361,18 +373,21 @@ SwigPyObject_format(const char* fmt, SwigPyObject *v)
PyObject *res = NULL; PyObject *res = NULL;
PyObject *args = PyTuple_New(1); PyObject *args = PyTuple_New(1);
if (args) { if (args) {
if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { PyObject *val = SwigPyObject_long(v);
PyObject *ofmt = SWIG_Python_str_FromChar(fmt); if (val) {
PyObject *ofmt;
PyTuple_SET_ITEM(args, 0, val);
ofmt = SWIG_Python_str_FromChar(fmt);
if (ofmt) { if (ofmt) {
#if PY_VERSION_HEX >= 0x03000000 #if PY_VERSION_HEX >= 0x03000000
res = PyUnicode_Format(ofmt,args); res = PyUnicode_Format(ofmt,args);
#else #else
res = PyString_Format(ofmt,args); res = PyString_Format(ofmt,args);
#endif #endif
Py_DECREF(ofmt); Py_DECREF(ofmt);
} }
Py_DECREF(args);
} }
Py_DECREF(args);
} }
return res; return res;
} }
@ -394,18 +409,23 @@ SwigPyObject_repr(SwigPyObject *v)
{ {
const char *name = SWIG_TypePrettyName(v->ty); const char *name = SWIG_TypePrettyName(v->ty);
PyObject *repr = SWIG_Python_str_FromFormat("<Swig Object of type '%s' at %p>", (name ? name : "unknown"), (void *)v); PyObject *repr = SWIG_Python_str_FromFormat("<Swig Object of type '%s' at %p>", (name ? name : "unknown"), (void *)v);
if (v->next) { if (repr && v->next) {
PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next);
if (nrep) {
# if PY_VERSION_HEX >= 0x03000000 # if PY_VERSION_HEX >= 0x03000000
PyObject *joined = PyUnicode_Concat(repr, nrep); PyObject *joined = PyUnicode_Concat(repr, nrep);
Py_DecRef(repr); Py_DecRef(repr);
Py_DecRef(nrep); Py_DecRef(nrep);
repr = joined; repr = joined;
# else # else
PyString_ConcatAndDel(&repr,nrep); PyString_ConcatAndDel(&repr,nrep);
# endif # endif
} else {
Py_DecRef(repr);
repr = NULL;
}
} }
return repr; return repr;
} }
/* We need a version taking two PyObject* parameters so it's a valid /* We need a version taking two PyObject* parameters so it's a valid
@ -501,8 +521,12 @@ SwigPyObject_dealloc(PyObject *v)
if (data->delargs) { if (data->delargs) {
/* we need to create a temporary object to carry the destroy operation */ /* we need to create a temporary object to carry the destroy operation */
PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0);
res = SWIG_Python_CallFunctor(destroy, tmp); if (tmp) {
Py_DECREF(tmp); res = SWIG_Python_CallFunctor(destroy, tmp);
} else {
res = 0;
}
Py_XDECREF(tmp);
} else { } else {
PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); PyCFunction meth = PyCFunction_GET_FUNCTION(destroy);
PyObject *mself = PyCFunction_GET_SELF(destroy); PyObject *mself = PyCFunction_GET_SELF(destroy);
@ -523,6 +547,9 @@ SwigPyObject_dealloc(PyObject *v)
#endif #endif
} }
Py_XDECREF(next); Py_XDECREF(next);
#ifdef SWIGPYTHON_BUILTIN
Py_XDECREF(sobj->dict);
#endif
PyObject_DEL(v); PyObject_DEL(v);
} }
@ -578,9 +605,9 @@ SwigPyObject_own(PyObject *v, PyObject *args)
PyObject *obj = PyBool_FromLong(sobj->own); PyObject *obj = PyBool_FromLong(sobj->own);
if (val) { if (val) {
if (PyObject_IsTrue(val)) { if (PyObject_IsTrue(val)) {
SwigPyObject_acquire(v,args); Py_DECREF(SwigPyObject_acquire(v,args));
} else { } else {
SwigPyObject_disown(v,args); Py_DECREF(SwigPyObject_disown(v,args));
} }
} }
return obj; return obj;
@ -725,7 +752,7 @@ SwigPyObject_TypeOnce(void) {
}; };
swigpyobject_type = tmp; swigpyobject_type = tmp;
type_init = 1; type_init = 1;
if (PyType_Ready(&swigpyobject_type) < 0) if (PyType_Ready(&swigpyobject_type) != 0)
return NULL; return NULL;
} }
return &swigpyobject_type; return &swigpyobject_type;
@ -740,6 +767,9 @@ SwigPyObject_New(void *ptr, swig_type_info *ty, int own)
sobj->ty = ty; sobj->ty = ty;
sobj->own = own; sobj->own = own;
sobj->next = 0; sobj->next = 0;
#ifdef SWIGPYTHON_BUILTIN
sobj->dict = 0;
#endif
} }
return (PyObject *)sobj; return (PyObject *)sobj;
} }
@ -892,7 +922,7 @@ SwigPyPacked_TypeOnce(void) {
}; };
swigpypacked_type = tmp; swigpypacked_type = tmp;
type_init = 1; type_init = 1;
if (PyType_Ready(&swigpypacked_type) < 0) if (PyType_Ready(&swigpypacked_type) != 0)
return NULL; return NULL;
} }
return &swigpypacked_type; return &swigpypacked_type;
@ -1200,12 +1230,17 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) #if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
PyObject **dictptr = _PyObject_GetDictPtr(inst); PyObject **dictptr = _PyObject_GetDictPtr(inst);
if (dictptr != NULL) { if (dictptr != NULL) {
PyObject *dict = *dictptr; PyObject *dict = *dictptr;
if (dict == NULL) { if (dict == NULL) {
dict = PyDict_New(); dict = PyDict_New();
*dictptr = dict; *dictptr = dict;
PyDict_SetItem(dict, SWIG_This(), swig_this); }
} if (dict) {
PyDict_SetItem(dict, SWIG_This(), swig_this);
} else{
Py_DECREF(inst);
inst = 0;
}
} }
#else #else
if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) { if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
@ -1256,7 +1291,11 @@ SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
dict = PyDict_New(); dict = PyDict_New();
*dictptr = dict; *dictptr = dict;
} }
return PyDict_SetItem(dict, SWIG_This(), swig_this); if (dict) {
return PyDict_SetItem(dict, SWIG_This(), swig_this);
} else{
return -1;
}
} }
#endif #endif
return PyObject_SetAttr(inst, SWIG_This(), swig_this); return PyObject_SetAttr(inst, SWIG_This(), swig_this);
@ -1271,7 +1310,7 @@ SWIG_Python_InitShadowInstance(PyObject *args) {
} else { } else {
SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]);
if (sthis) { if (sthis) {
SwigPyObject_append((PyObject*) sthis, obj[1]); Py_DECREF(SwigPyObject_append((PyObject*) sthis, obj[1]));
} else { } else {
if (SWIG_Python_SetSwigThis(obj[0], obj[1]) != 0) if (SWIG_Python_SetSwigThis(obj[0], obj[1]) != 0)
return NULL; return NULL;
@ -1310,7 +1349,9 @@ SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int f
} else { } else {
newobj = PyObject_New(SwigPyObject, clientdata->pytype); newobj = PyObject_New(SwigPyObject, clientdata->pytype);
#ifdef SWIGPYTHON_BUILTIN #ifdef SWIGPYTHON_BUILTIN
newobj->dict = 0; if (newobj) {
newobj->dict = 0;
}
#endif #endif
} }
if (newobj) { if (newobj) {
@ -1349,6 +1390,13 @@ SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
void *SWIG_ReturnGlobalTypeList(void *); void *SWIG_ReturnGlobalTypeList(void *);
#endif #endif
/* The python cached type query */
SWIGRUNTIME PyObject *
SWIG_Python_TypeCache(void) {
static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New();
return cache;
}
SWIGRUNTIME swig_module_info * SWIGRUNTIME swig_module_info *
SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) { SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) {
static void *type_pointer = (void *)0; static void *type_pointer = (void *)0;
@ -1377,11 +1425,13 @@ SWIG_Python_DestroyModule(PyObject *obj)
swig_type_info *ty = types[i]; swig_type_info *ty = types[i];
if (ty->owndata) { if (ty->owndata) {
SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; SwigPyClientData *data = (SwigPyClientData *) ty->clientdata;
ty->clientdata = 0;
if (data) SwigPyClientData_Del(data); if (data) SwigPyClientData_Del(data);
} }
} }
Py_DECREF(SWIG_This()); Py_DECREF(SWIG_This());
Swig_This_global = NULL; Swig_This_global = NULL;
Py_DECREF(SWIG_Python_TypeCache());
} }
SWIGRUNTIME void SWIGRUNTIME void
@ -1395,19 +1445,14 @@ SWIG_Python_SetModule(swig_module_info *swig_module) {
#endif #endif
PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule);
if (pointer && module) { if (pointer && module) {
PyModule_AddObject(module, "type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); if (PyModule_AddObject(module, "type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer) != 0) {
Py_DECREF(pointer);
}
} else { } else {
Py_XDECREF(pointer); Py_XDECREF(pointer);
} }
} }
/* The python cached type query */
SWIGRUNTIME PyObject *
SWIG_Python_TypeCache(void) {
static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New();
return cache;
}
SWIGRUNTIME swig_type_info * SWIGRUNTIME swig_type_info *
SWIG_Python_TypeQuery(const char *type) SWIG_Python_TypeQuery(const char *type)
{ {
@ -1422,8 +1467,10 @@ SWIG_Python_TypeQuery(const char *type)
descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type);
if (descriptor) { if (descriptor) {
obj = PyCapsule_New((void*) descriptor, NULL, NULL); obj = PyCapsule_New((void*) descriptor, NULL, NULL);
PyDict_SetItem(cache, key, obj); if (obj) {
Py_DECREF(obj); PyDict_SetItem(cache, key, obj);
Py_DECREF(obj);
}
} }
} }
Py_DECREF(key); Py_DECREF(key);
@ -1566,7 +1613,7 @@ SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) {
} }
if (!tp->tp_dict) { if (!tp->tp_dict) {
if (PyType_Ready(tp) < 0) if (PyType_Ready(tp) != 0)
goto done; goto done;
} }
@ -1581,7 +1628,7 @@ SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) {
} else { } else {
encoded_name = PyUnicode_AsUTF8String(name); encoded_name = PyUnicode_AsUTF8String(name);
if (!encoded_name) if (!encoded_name)
return -1; goto done;
} }
PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name));
Py_DECREF(encoded_name); Py_DECREF(encoded_name);