[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