[PyQt] double free issue with OUT-argument

Phil Thompson phil at riverbankcomputing.com
Mon Feb 15 11:36:12 GMT 2010


On Sat, 13 Feb 2010 18:34:58 +0100, "Diez B. Roggisch" <deets at web.de>
wrote:
> Hi,
> 
> wrapping happily away a 3D-engine, I encounter the following problem:
> 
>  >>> import irrlicht
>  >>> core = irrlicht.irr.core
>  >>> q = core.quaternion()
>  >>> q.toEuler()
> python(3701) malloc: *** error for object 0x474b70: double free
> *** set a breakpoint in malloc_error_break to debug
> (0.0, -0.0, 0.0)
> 
> 
> This is the declaration of toEuler in .sip:
> 
>        void toEuler(irr::core::vector3df& euler /Out/) const;
> 
> As you can see, it's supposed to modify a passed vector in place. 
> However, I declared vectors to be converted from & to tuples, by this 
> code mapping:
> 
> %MappedType irr::core::vector3df
> {
> %TypeHeaderCode
> #include <vector3d.h>
> %End
> 
> %ConvertFromTypeCode
>    if (!sipCpp)
>      return PyTuple_New(0);
>    irr::core::vector3df *v = (irr::core::vector3df *)sipCpp;
>    return PyTuple_Pack(3, 
>
PyFloat_FromDouble(v->X),PyFloat_FromDouble(v->Y),PyFloat_FromDouble(v->Z));
> %End
> 
> %ConvertToTypeCode
>     if (sipIsErr == NULL) {
>       if(PySequence_Check(sipPy) && PySequence_Length(sipPy) == 3) {
>         for(int j = 0; j < 3; j++) {
> 	 PyObject *v = PySequence_GetItem(sipPy, j);
> 	 if(!PyFloat_Check(v) && !PyInt_Check(v)) {
> 	   return false;
> 	 }
>         }
>         return true;
>       }
>       return false;
>     }
>    if (sipPy == Py_None) {
>      *sipCppPtr = NULL;
>      return 0;
>    }
> 
>    irr::core::vector3df *v = new irr::core::vector3df();
>    PyErr_Clear();
>    irr::core::vector3df &t = *v;
>    if(PyArg_ParseTuple(sipPy, "fff", &t.X, &t.Y, &t.Z)) {
>      *sipCppPtr = v;
>      return 1;
>    } else {
>      delete v;
>      *sipIsErr = 1;
>      return 0;
>    }
> %End
> };
> 
> Looking at the generated code, it seems to me it is perfectly fine - it 
> creates a new vector instance, passes that in, converts it to a tuple, 
> and deletes it.
> 
> extern "C" {static PyObject *meth_irr_core_quaternion_toEuler(PyObject 
> *, PyObject *);}
> static PyObject *meth_irr_core_quaternion_toEuler(PyObject *sipSelf, 
> PyObject *sipArgs)
> {
>      int sipArgsParsed = 0;
> 
>      {
>          irr::core::vector3df * a0;
>          irr::core::quaternion *sipCpp;
> 
>          if 
>
(sipParseArgs(&sipArgsParsed,sipArgs,"B",&sipSelf,sipType_irr_core_quaternion,&sipCpp))
>          {
>              PyObject *sipResult;
>              a0 = new irr::core::vector3df();
> 
>              sipCpp->toEuler(*a0);
> 
>              sipResult = 
> sipConvertFromNewType(a0,sipType_irr_core_vector3df,NULL);
>              delete a0;
> 
>              return sipResult;
>          }
>      }
> 
>      /* Raise an exception if the arguments couldn't be parsed. */
>      sipNoMethod(sipArgsParsed,sipName_quaternion,sipName_toEuler);
> 
>      return NULL;
> }
> 
> 
> I don't understand the behavior - anything I miss?

Which version of SIP? I think this is fixed in SIP v4.10.

Unrelated...

There is a memory leak in your %ConvertToTypeCode as PySequence_GetItem()
returns a new reference to the item. However you should use the PyTuple
functions anyway (which don't return a new reference) because you are using
PyArg_ParseTuple() to do the conversion.

Phil


More information about the PyQt mailing list