diff --git a/CHANGES.current b/CHANGES.current index 8306b17e2..19b2e90c0 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -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 diff --git a/Lib/python/pyerrors.swg b/Lib/python/pyerrors.swg index dcd99c939..2628de8e6 100644 --- a/Lib/python/pyerrors.swg +++ b/Lib/python/pyerrors.swg @@ -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); diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 63ff82ff8..f32afb07e 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -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); @@ -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__"); @@ -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; } @@ -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 =====================*/ @@ -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; } @@ -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; } @@ -523,6 +541,9 @@ SwigPyObject_dealloc(PyObject *v) #endif } Py_XDECREF(next); +#ifdef SWIGPYTHON_BUILTIN + Py_XDECREF(sobj->dict); +#endif PyObject_DEL(v); } @@ -582,6 +603,7 @@ SwigPyObject_own(PyObject *v, PyObject *args) } else { SwigPyObject_disown(v,args); } + Py_DECREF(Py_None); } return obj; } @@ -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; } @@ -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) { @@ -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; @@ -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 @@ -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) {