diff --git a/CHANGES.current b/CHANGES.current index 65cc144bb..0b6e2efe4 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,21 @@ Version 1.3.39 (in progress) ============================ +2009-03-19: bhy + [Python] Fix the memory leak related to Python 3 unicode and C char* conversion, + which can be shown in the following example before this fix: + + from li_cstring import * + i=0 + while True: + i += 1 + n = str(i)*10 + test3(n) + + This fix affected SWIG_AsCharPtrAndSize() so you cannot call this function with + a null alloc and non-null cptr argument in Python 3, otherwise a runtime error + will be raised. + 2009-03-18: wsfulton [C#] std::vector wrapper improvements for .NET 2 and also providing the necessary machinery to use the std::vector wrappers with more advanced features such diff --git a/Lib/python/pyerrors.swg b/Lib/python/pyerrors.swg index 63f0344e4..fe7313554 100644 --- a/Lib/python/pyerrors.swg +++ b/Lib/python/pyerrors.swg @@ -55,11 +55,13 @@ SWIG_Python_AddErrorMsg(const char* mesg) if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); if (value) { + char *tmp; PyObject *old_str = PyObject_Str(value); PyErr_Clear(); Py_XINCREF(type); - PyErr_Format(type, "%s %s", SWIG_Python_str_AsChar(old_str), mesg); + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); + SWIG_Python_str_DelForPy3(tmp); Py_DECREF(old_str); Py_DECREF(value); } else { diff --git a/Lib/python/pyhead.swg b/Lib/python/pyhead.swg index ecafc46c8..732d4689e 100644 --- a/Lib/python/pyhead.swg +++ b/Lib/python/pyhead.swg @@ -21,17 +21,35 @@ # define SWIG_Python_str_FromFormat PyString_FromFormat #endif + +/* Warning: This function will allocate a new string in Python 3, + * so please call SWIG_Python_str_DelForPy3(x) to free the space. + */ SWIGINTERN char* SWIG_Python_str_AsChar(PyObject *str) { #if PY_VERSION_HEX >= 0x03000000 + char *cstr; + char *newstr; + int len; str = PyUnicode_AsUTF8String(str); - return PyBytes_AsString(str); + PyBytes_AsStringAndSize(str, &cstr, &len); + newstr = (char *) malloc(len+1); + memcpy(newstr, cstr, len+1); + Py_XDECREF(str); + return newstr; #else return PyString_AsString(str); #endif } +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) +#else +# define SWIG_Python_str_DelForPy3(x) +#endif + + SWIGINTERN PyObject* SWIG_Python_str_FromChar(const char *c) { diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg index 5fa50ecb8..286e7fb68 100644 --- a/Lib/python/pyinit.swg +++ b/Lib/python/pyinit.swg @@ -80,9 +80,11 @@ swig_varlink_str(swig_varlinkobject *v) { SWIGINTERN int swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + char *tmp; PyObject *str = swig_varlink_str(v); fprintf(fp,"Swig global variables "); - fprintf(fp,"%s\n", SWIG_Python_str_AsChar(str)); + fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str)); + SWIG_Python_str_DelForPy3(tmp); Py_DECREF(str); return 0; } diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 30021bb48..5a1b1230e 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -407,13 +407,16 @@ SwigPyObject_repr(SwigPyObject *v, PyObject *args) SWIGRUNTIME int SwigPyObject_print(SwigPyObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + char *str; #ifdef METH_NOARGS PyObject *repr = SwigPyObject_repr(v); #else PyObject *repr = SwigPyObject_repr(v, NULL); #endif if (repr) { - fputs(SWIG_Python_str_AsChar(repr), fp); + str = SWIG_Python_str_AsChar(repr); + fputs(str, fp); + SWIG_Python_str_DelForPy3(str); Py_DECREF(repr); return 0; } else { @@ -1474,21 +1477,23 @@ SWIG_Python_TypeQuery(const char *type) SWIGRUNTIME int SWIG_Python_AddErrMesg(const char* mesg, int infront) -{ +{ if (PyErr_Occurred()) { PyObject *type = 0; PyObject *value = 0; PyObject *traceback = 0; PyErr_Fetch(&type, &value, &traceback); if (value) { + char *tmp; PyObject *old_str = PyObject_Str(value); Py_XINCREF(type); PyErr_Clear(); if (infront) { - PyErr_Format(type, "%s %s", mesg, SWIG_Python_str_AsChar(old_str)); + PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str)); } else { - PyErr_Format(type, "%s %s", SWIG_Python_str_AsChar(old_str), mesg); + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); } + SWIG_Python_str_DelForPy3(tmp); Py_DECREF(old_str); } return 1; @@ -1540,6 +1545,7 @@ SWIG_Python_TypeError(const char *type, PyObject *obj) if (cstr) { PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", type, otype, cstr); + SWIG_Python_str_DelForPy3(cstr); } else { PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", type, otype); diff --git a/Lib/python/pystrings.swg b/Lib/python/pystrings.swg index 5a06792d7..1983037a5 100644 --- a/Lib/python/pystrings.swg +++ b/Lib/python/pystrings.swg @@ -6,19 +6,27 @@ SWIGINTERN int SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) { %#if PY_VERSION_HEX>=0x03000000 - if (PyUnicode_Check(obj)) + if (PyUnicode_Check(obj)) %#else - if (PyString_Check(obj)) + if (PyString_Check(obj)) %#endif { char *cstr; Py_ssize_t len; %#if PY_VERSION_HEX>=0x03000000 + if (!alloc && cptr) { + /* We can't allow converting without allocation, since the internal + representation of string in Python 3 is UCS-2/UCS-4 but we require + a UTF-8 representation. + TODO(bhy) More detailed explanation */ + return SWIG_RuntimeError; + } obj = PyUnicode_AsUTF8String(obj); PyBytes_AsStringAndSize(obj, &cstr, &len); + if(alloc) *alloc = SWIG_NEWOBJ; %#else PyString_AsStringAndSize(obj, &cstr, &len); %#endif - if (cptr) { + if (cptr) { if (alloc) { /* In python the user should not be able to modify the inner @@ -43,10 +51,16 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) *alloc = SWIG_OLDOBJ; } } else { + %#if PY_VERSION_HEX>=0x03000000 + assert(0); /* Should never reach here in Python 3 */ + %#endif *cptr = SWIG_Python_str_AsChar(obj); } } if (psize) *psize = len + 1; +%#if PY_VERSION_HEX>=0x03000000 + Py_XDECREF(obj); +%#endif return SWIG_OK; } else { swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();