[PyKDE] Bug in code for wrapped attributes
    Denis S. Otkidach 
    ods at strana.ru
       
    Sat Jul  2 09:19:46 BST 2005
    
    
  
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).
-- 
Denis S. Otkidach
http://www.python.ru/      [ru]
    
    
More information about the PyQt
mailing list