[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