<div dir="ltr"><br>Hi,<br><br>We experience crashes using sip 4.18 and 4.19, where it works fine using 4.17.<br>I have dug for a while in the code, and found out that in some cases, after object conversion into a class using its %ConvertToTypeCode, the object gets deleted after a cast to the wrong sip-derived class.<br><br>Let's say I have a C++ class AClass, with SIP bindings and conversion code from another type (int for instance) which instantiates a new AClass.<br><br>In another custom function (named print_float_or_aclass() in the example, which is quite pointless but it's just an example), the conversion code is invoked, the converted object is used, then sipReleaseType() is normally called. But this release destroys the object after cast to sipAClass, where it is really a AClass.<br><br>I tried to make a relatively small example to demonstrate the problem.<br><br>file: aclass.h<br><br>#ifndef ACLASS_H<br>#define ACLASS_H<br><br>class AClass<br>{<br>public:<br>  AClass( int x );<br>  AClass( const AClass & x );<br>  virtual ~AClass();<br><br>  int number() const;<br><br>private:<br>  int _number;<br>};<br><br>#endif<br><br>--<br><br>file: aclass.cpp<br><br>#include "aclass.h"<br><br><br>AClass::AClass( int x )<br>  : _number( x )<br>{<br>}<br><br>AClass::AClass( const AClass & x )<br>  : _number( x.number() )<br>{<br>}<br><br>AClass::~AClass()<br>{<br>}<br><br><br>int AClass::number() const<br>{<br>  return _number;<br>}<br><br>--<br><br>file: aclass.sip<br><br><br>%Module aclass<br><br>class AClass<br>{<br>public:<br>%TypeHeaderCode<br>#include "aclass.h"<br>%End<br><br>%ConvertToTypeCode<br><br>  if( sipIsErr == NULL )<br>  {<br>    if( PyInt_Check( sipPy ) )<br>      return 1;<br>    else<br>      return 0;<br>  }<br>  else<br>  {<br>    std::cout << "ConvertToTypeCode, instantiate new AClass\n";<br>    AClass *aclass = new AClass( PyInt_AsLong( sipPy ) );<br>    *sipCppPtr = aclass;<br>    return sipGetState( sipTransferObj );<br>  }<br><br>%End<br><br>  AClass( int x );<br>  AClass( const AClass & x );<br>  virtual ~AClass();<br>  int number() const;<br>};<br><br>%ModuleCode<br>#include "aclass.h"<br>#include <iostream><br>%End<br><br>void print_float_or_aclass( SIP_PYOBJECT );<br>%MethodCode<br>  if( PyFloat_Check( a0 ) )<br>    std::cout << "float: " << PyFloat_AsDouble( a0 ) << std::endl;<br>  else<br>  {<br>    int state = 0;<br>    void *obj = sipForceConvertToType( a0, sipType_AClass,<br>          0, 0, &state, &sipIsErr );<br>    if( obj )<br>    {<br>      AClass *o = reinterpret_cast<AClass *>( obj );<br>      std::cout << "AClass: " << o->number() << std::endl;<br>      sipReleaseType( obj, sipType_AClass, state );<br>    }<br>  }<br>%End<br><br>--<br><br>this (very) minimal Makefile can be used to build it from the source directory:<br><br>PYTHON_INCLUDE=/usr/include/python2.7<br><br># comment out the following 2 lines and uncomment the next to use sip 4.19<br>SIP_INCLUDE=/usr/include/python2.7<br>SIP_EXE=sip<br><br># SIP_INCLUDE=/home/someone/sip-4.19.2/include<br># SIP_EXE=/home/someone/sip-4.19.2/bin/sip<br><br>all:    aclass.so<br><br>sipaclasspart0.cpp: aclass.sip aclass.cpp aclass.h<br>    $(SIP_EXE) -j1 -c . aclass.sip<br><br>aclass.so:    sipaclasspart0.cpp<br>    g++ -fPIC -shared -o aclass.so -I$(SIP_INCLUDE) -I$(PYTHON_INCLUDE) sipaclasspart0.cpp aclass.cpp<br><br>--<br><br>When using for instance aclass.print_float_or_aclass(12), 12 (int) gets converted to a AClass object, which is released after use.<br>But the release code does not do the same when using sip 4.17 or 4.18/4.19. We can print things by slighty modifying the code of the release_AClass() function in the generated file sipclasspart0.cpp:<br><br>with sip 4.19.2:<br><br>/* Call the instance's destructor. */<br>extern "C" {static void release_AClass(void *, int);}<br>static void release_AClass(void *sipCppV, int sipIsDerived)<br>{<br>    std::cout << "release_AClass, sipIsDerived: " << sipIsDerived << std::endl;<br>    if (sipIsDerived)<br>    {<br>        std::cout << "delete derived\n";<br>        delete reinterpret_cast<sipAClass *>(sipCppV);<br>    }<br>    else<br>    {<br>        std::cout << "delete AClass\n";<br>        delete reinterpret_cast< ::AClass *>(sipCppV);<br>    }<br>}<br><br><br>with sip 4.17:<br><br>/* Call the instance's destructor. */<br>extern "C" {static void release_AClass(void *, int);}<br>static void release_AClass(void *sipCppV,int sipState)<br>{<br>    std::cout << "release_AClass, sipState: " << sipState << std::endl;<br>    if (sipState & SIP_DERIVED_CLASS)<br>    {<br>        std::cout << "delete derived\n";<br>        delete reinterpret_cast<sipAClass *>(sipCppV);<br>    }<br>    else<br>    {<br>        std::cout << "delete AClass\n";<br>        delete reinterpret_cast<AClass *>(sipCppV);<br>    }<br>}<br><br>Then after rebuilding the module, we use the function:<br><br>>>> import aclass<br>>>> aclass.print_float_or_aclass(12)<br><br>with sip 4.17, it prints:<br><br>ConvertToTypeCode, instantiate new AClass<br>AClass: 12<br>release_AClass, sipState: 1<br>delete AClass<br><br>(so it is not the derived class case)<br><br>with sip 4.19 (I have changed PYTHONPATH to point to the sip 4.19 module before running), it prints:<br><br>ConvertToTypeCode, instantiate new AClass<br>AClass: 12<br>release_AClass, sipIsDerived: 1<br>delete derived<br><br>(note that it does not crash every time, but seems wrong anyway)<br><br>Here the release code is called with sipIsDerived argument set to 1. However 1 is actually directly the "state" value set in %ConvertToTypeCode, which does not mean SIP_DERIVED_CLASS (which value is 2), but SIP_TEMPORARY.<br><br>In the source code of siplib (<a href="http://siplib.c.in">siplib.c.in</a>), the code of sip_api_release_type() calls the release function of the type object with complete "state" value, not a boolean meaning if it is derived.<br><br>So I think there is a bug there.<br>Am I right ?<br><br>Regards,<br>Denis<br><br></div>