Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-107

Wrong PyObject reference counting leads to memory leak in QMap->PyDict converter template code of PySide/QtCore/typesystem_core_common.xml

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • None
    • 1.1.0, 1.1.1, 1.1.2
    • PySide
    • None
    • 6df4b307c5aec758ad954ab8717f5e85b44e2ae5

    Description

      While migrating our project from PySide v1.0.9 to v1.1.1 we've noticed memory leak.
      We've found problem in PySide/QtCore/typesystem_core_common.xml

      There's a converter template code for QMap->PyDict conversion:

       
        <template name="cppmap_to_pymap_convertion">
          PyObject* %out = PyDict_New();
          %INTYPE::const_iterator it = %in.begin();
          for (; it != %in.end(); ++it) {
              %INTYPE_0 key = it.key();
              %INTYPE_1 value = it.value();
              PyDict_SetItem(%out,
                             %CONVERTTOPYTHON[%INTYPE_0](key),
                             %CONVERTTOPYTHON[%INTYPE_1](value));
          }
          return %out;
        </template>
      

      But!
      Python C-API documentation and sources tell us that PyDict_SetItem() INCREFs both the key and the value.

      In Python 2.7.3 sources (http://svn.python.org/view/python/trunk/Objects/dictobject.c?view=markup)
      Objects/dictobject.c: PyDict_SetItem() has

      Py_INCREF(value);
      Py_INCREF(key);
      

      at lines: 773,774

      Since PyDict_SetItem() doesn't "steal" a reference to key and value, one should do Py_DECREF() manualy to key and value after call to PyDict_SetItem().

      So, correct template looks following:

        <template name="cppmap_to_pymap_convertion">
          PyObject* %out = PyDict_New();
          %INTYPE::const_iterator it = %in.begin();
          for (; it != %in.end(); ++it) {
              %INTYPE_0 key = it.key();
              %INTYPE_1 value = it.value();
              PyObject* pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
              PyObject* pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
              PyDict_SetItem(%out, pyKey, pyValue);
              Py_DECREF(pyKey);
              Py_DECREF(pyValue);
          }
          return %out;
        </template>
      

      We're using PySide v1.1.1.
      We've checked latest pyside-qt4.8+1.1.2 and bug seems to be there also.
      Corresponding Patch to for PySide 1.1.1 (file attached to ticket) is following:

      --- typesystem_core_common.xml.v1.1.1    2012-04-19 03:06:40.000000000 +0400
      +++ typesystem_core_common.xml    2012-09-10 12:32:33.214677526 +0400
      @@ -658,9 +658,11 @@
           for (; it != %in.end(); ++it) {
               %INTYPE_0 key = it.key();
               %INTYPE_1 value = it.value();
      -        PyDict_SetItem(%out,
      -                       %CONVERTTOPYTHON[%INTYPE_0](key),
      -                       %CONVERTTOPYTHON[%INTYPE_1](value));
      +        PyObject* pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
      +        PyObject* pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
      +        PyDict_SetItem(%out, pyKey, pyValue);
      +        Py_DECREF(pyKey);
      +        Py_DECREF(pyValue);
           }
           return %out;
         </template>
      

      Please apply this little patch, we're looking forward to help to maintain and use future versions of PySide.

      Best regards.
      Dennis Shilko.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            jpe John Ehresman
            dennis.v. Dennis Shilko
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes