[PyKDE] Bug in code for wrapped attributes

Phil Thompson phil at riverbankcomputing.co.uk
Sat Jul 2 12:05:49 BST 2005


On Saturday 02 July 2005 9:19 am, Denis S. Otkidach wrote:
> Below is a code generated for wrapped attribute (PyObject* in original
> class, SIP_PYOBJECT in SIP spec):
>
> -->8--
> static PyObject *var_MyClass_myAttr(PyObject *sipSelf,PyObject *sipPy)
> {
>         PyObject * sipVal;
>         MyClass *sipCpp = reinterpret_cast<MyClass
> *>(sipGetCppPtr((sipWrapper *)sipSelf,sipClass_MyClass));
>
>         if (!sipCpp)
>                 return NULL;
>
>         if (sipPy == NULL)
>         {
>                 sipVal = sipCpp -> myAttr;
>
>                 Py_XINCREF(sipVal);
>
>                 return sipVal;
>         }
>
>         sipVal = sipPy;
>
>         if (PyErr_Occurred() != NULL)
>         {
>                
> sipBadSetType(sipNm_MyModule_MyClass,sipNm_MyModule_myAttr); return NULL;
>         }
>
>         Py_INCREF(sipVal); // <-- missed increment
>         sipCpp -> myAttr = sipVal;
>
>         Py_INCREF(Py_None);
>         return Py_None;
> }
> -->8--
>
> There is no line marked with "missed increment" in generated code, so
> attribute value has incorrect reference count causing strange behavior
> and/or segmentation fault.
>
> The story about how I discovered this bug is quite interesting.  I've
> written test script looking like the following:
>
> foo = MyModule.Foo()
> foo.myAttr = lambda *args: args
> bar = foo.createBar()  # bar constructor assignes foo.myAttr to bar.myAttr
> def newMyAttr(*args):
>     print 'newMyAttr called with', args
> bar.doSmth() # this method calls bar.myAttr
>
> I defined newMyAttr as replacement for earlier assigned function. Then I
> run the script and so expected output "newMyAttr called with (2, 1, 2)".
>  Just a minute later I discovered that I'd actually forgotten to assign
> newMyAttr to bar.myAttr!  Then why it's called?!  Did Python conjectured
> that I wanted to assign newMyAttr itself?  Looked like a mistery.  I
> added "print bar.myAttr" before and after newMyAttr definition and saw:
>
> converter: <function <lambda> at 0x30c994>
> converter: <function newMyAttr at 0x30c994>
>
> Hey, these objects have the same address!  Farther experiments proved my
> guess that lambda object was destroyed.  In fact, after changing
>
> foo.myAttr = lambda *args: args
>
> into
>
> f = lambda *args: args
> foo.myAttr = f
>
> the problem disappeared.  Putting "print sys.getrefcount(f)" showed 2
> when 3 expected (f itself, foo.myAttr, and argument to getrefcount).

Fixed in tonight's snapshot.

Thanks,
Phil




More information about the PyQt mailing list