Skip to content

Commit

Permalink
[Python] Fix memory leaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-rogers-wdc committed May 12, 2021
1 parent b671a37 commit 84ff84f
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 29 deletions.
26 changes: 26 additions & 0 deletions CHANGES.current
Expand Up @@ -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)
===========================

2021-05-12: adr26
#1985 [Python] 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-04: olly
[PHP] #1982 #1457 https://sourceforge.net/p/swig/bugs/1339/
SWIG now only use PHP's C API to implement its wrappers, and no
Expand Down
8 changes: 6 additions & 2 deletions Lib/python/pyerrors.swg
Expand Up @@ -95,8 +95,12 @@ SWIG_Python_RaiseOrModifyTypeError(const char *message)
#else
newvalue = PyString_FromFormat("%s\nAdditional information:\n%s", PyString_AsString(value), message);
#endif
Py_XDECREF(value);
PyErr_Restore(type, newvalue, traceback);
if (newvalue) {
Py_XDECREF(value);
PyErr_Restore(type, newvalue, traceback);
} else {
PyErr_Restore(type, value, traceback);
}
} else {
/* Raise TypeError using given message */
PyErr_SetString(PyExc_TypeError, message);
Expand Down
85 changes: 58 additions & 27 deletions Lib/python/pyrun.swg
Expand Up @@ -127,7 +127,11 @@ SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) {
if (!PyList_Check(result)) {
PyObject *o2 = result;
result = PyList_New(1);
PyList_SetItem(result, 0, o2);
if (result) {
PyList_SET_ITEM(result, 0, o2);
} else {
return o2;
}
}
PyList_Append(result,obj);
Py_DECREF(obj);
Expand Down Expand Up @@ -279,18 +283,26 @@ SwigPyClientData_New(PyObject* obj)
/* the newraw method and newargs arguments used to create a new raw instance */
if (PyClass_Check(obj)) {
data->newraw = 0;
data->newargs = obj;
Py_INCREF(obj);
data->newargs = obj;
} else {
data->newraw = PyObject_GetAttrString(data->klass, "__new__");
if (data->newraw) {
Py_INCREF(data->newraw);
data->newargs = PyTuple_New(1);
PyTuple_SetItem(data->newargs, 0, obj);
data->newargs = PyTuple_New(1);
if (data->newargs) {
Py_INCREF(obj);
PyTuple_SET_ITEM(data->newargs, 0, obj);
} else {
Py_DECREF(data->newraw);
Py_DECREF(data->klass);
free(data);
PyErr_NoMemory();
return 0;
}
} else {
data->newargs = obj;
Py_INCREF(obj);
data->newargs = obj;
}
Py_INCREF(data->newargs);
}
/* the destroy method, aka as the C++ delete method */
data->destroy = PyObject_GetAttrString(data->klass, "__swig_destroy__");
Expand All @@ -299,10 +311,7 @@ SwigPyClientData_New(PyObject* obj)
data->destroy = 0;
}
if (data->destroy) {
int flags;
Py_INCREF(data->destroy);
flags = PyCFunction_GET_FLAGS(data->destroy);
data->delargs = !(flags & (METH_O));
data->delargs = !(PyCFunction_GET_FLAGS(data->destroy) & METH_O);
} else {
data->delargs = 0;
}
Expand All @@ -313,10 +322,13 @@ SwigPyClientData_New(PyObject* obj)
}

SWIGRUNTIME void
SwigPyClientData_Del(SwigPyClientData *data) {
SwigPyClientData_Del(SwigPyClientData *data)
{
Py_XDECREF(data->klass);
Py_XDECREF(data->newraw);
Py_XDECREF(data->newargs);
Py_XDECREF(data->destroy);
free(data);
}

/* =============== SwigPyObject =====================*/
Expand All @@ -343,6 +355,9 @@ SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
if (!sobj->dict)
sobj->dict = PyDict_New();

if (!sobj->dict)
return PyErr_NoMemory();

Py_INCREF(sobj->dict);
return sobj->dict;
}
Expand All @@ -361,18 +376,21 @@ SwigPyObject_format(const char* fmt, SwigPyObject *v)
PyObject *res = NULL;
PyObject *args = PyTuple_New(1);
if (args) {
if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) {
PyObject *ofmt = SWIG_Python_str_FromChar(fmt);
PyObject *val = SwigPyObject_long(v);
if (val) {
PyObject *ofmt;
PyTuple_SET_ITEM(args, 0, val);
ofmt = SWIG_Python_str_FromChar(fmt);
if (ofmt) {
#if PY_VERSION_HEX >= 0x03000000
res = PyUnicode_Format(ofmt,args);
res = PyUnicode_Format(ofmt,args);
#else
res = PyString_Format(ofmt,args);
res = PyString_Format(ofmt,args);
#endif
Py_DECREF(ofmt);
Py_DECREF(ofmt);
}
Py_DECREF(args);
}
Py_DECREF(args);
}
return res;
}
Expand Down Expand Up @@ -523,6 +541,9 @@ SwigPyObject_dealloc(PyObject *v)
#endif
}
Py_XDECREF(next);
#ifdef SWIGPYTHON_BUILTIN
Py_XDECREF(sobj->dict);
#endif
PyObject_DEL(v);
}

Expand Down Expand Up @@ -582,6 +603,7 @@ SwigPyObject_own(PyObject *v, PyObject *args)
} else {
SwigPyObject_disown(v,args);
}
Py_DECREF(Py_None);
}
return obj;
}
Expand Down Expand Up @@ -740,6 +762,9 @@ SwigPyObject_New(void *ptr, swig_type_info *ty, int own)
sobj->ty = ty;
sobj->own = own;
sobj->next = 0;
#ifdef SWIGPYTHON_BUILTIN
sobj->dict = 0;
#endif
}
return (PyObject *)sobj;
}
Expand Down Expand Up @@ -1310,7 +1335,9 @@ SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int f
} else {
newobj = PyObject_New(SwigPyObject, clientdata->pytype);
#ifdef SWIGPYTHON_BUILTIN
newobj->dict = 0;
if (newobj) {
newobj->dict = 0;
}
#endif
}
if (newobj) {
Expand Down Expand Up @@ -1349,6 +1376,13 @@ SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
void *SWIG_ReturnGlobalTypeList(void *);
#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 *
SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) {
static void *type_pointer = (void *)0;
Expand Down Expand Up @@ -1377,11 +1411,13 @@ SWIG_Python_DestroyModule(PyObject *obj)
swig_type_info *ty = types[i];
if (ty->owndata) {
SwigPyClientData *data = (SwigPyClientData *) ty->clientdata;
ty->clientdata = 0;
if (data) SwigPyClientData_Del(data);
}
}
Py_DECREF(SWIG_This());
Swig_This_global = NULL;
Py_DECREF(SWIG_Python_TypeCache());
}

SWIGRUNTIME void
Expand All @@ -1395,19 +1431,14 @@ 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) {
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 {
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 *
SWIG_Python_TypeQuery(const char *type)
{
Expand Down

0 comments on commit 84ff84f

Please sign in to comment.