[PyQt] Crash with QMetaObject support

Giovanni Bajo rasky at develer.com
Wed May 16 15:58:31 BST 2007


Hi Phil,

[fix at the end of the mail]

Using Qt 4.2.2, PyQt 4.2, SIP 4.6,
I get a segfault in QMetaObject::indexOfSlot() 
(corelib\kernel\qmetaobject.cpp):

int QMetaObject::indexOfSlot(const char *slot) const
{
     int i = -1;
     const QMetaObject *m = this;
     while (m && i < 0) {
         for (i = priv(m->d.data)->methodCount-1; i >= 0; --i)
             if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & 
MethodTypeMask) == MethodSlot
                 && strcmp(slot, m->d.stringdata
                        + m->d.data[priv(m->d.data)->methodData + 5*i]) 
== 0) {
                 i += m->methodOffset();
                 break;
             }
         m = m->d.superdata;
     }
     return i;
}


The crash is within the if condition, when it tries to access that 
data[]. The problem is that the offset within data[] computed by the 
expression:

    priv(m->d.data)->methodData + 5*i + 4

is invalid. "slot" points to the string "deleteLater()" in memory. "i" is 1.

m->d.stringdata is:

0x0A488F40  50 79 51 74 50 72 6f 78  PyQtProx
0x0A488F48  79 00 00 41 42 4f 55 54  y..ABOUT
0x0A488F50  5f 54 4f 5f 53 48 4f 57  _TO_SHOW
0x0A488F58  28 29 00 00 00 00 00 00  ()......
0x0A488F60  0a 00 05 00 04 01 0c 00  ........
0x0A488F68  a0 3c e3 00 10 38 80 09   <ã..8€.
0x0A488F70  a8 8e 48 0a 00 00 00 00  ¨ŽH.....
0x0A488F78  b0 a1 42 0a 00 00 00 00  °¡B.....
0x0A488F80  00 00 00 00 00 00 00 00  ........
0x0A488F88  00 00 00 00 00 00 00 00  ........
(not sure how long the buffer is)

m->d.data is:

0x0A488FB8  01 00 00 00 00 00 00 00  ........
0x0A488FC0  00 00 00 00 00 00 00 00  ........
0x0A488FC8  02 00 00 00 0a 00 00 00  ........
0x0A488FD0  00 00 00 00 00 00 00 00  ........
0x0A488FD8  00 00 00 00 00 00 00 00  ........
0x0A488FE0  0b 00 00 00 0a 00 00 00  ........
0x0A488FE8  0a 00 00 00 0a 00 00 00  ........
0x0A488FF0  05 00 00 00 23 00 00 00  ....#...
0x0A488FF8  00 00 00 00 00 00 00 00  ........
0x0A489000  ?? ?? ?? ?? ?? ?? ?? ??
0x0A489008  ?? ?? ?? ?? ?? ?? ?? ??
(notice that 0xA489000 is not-allocated memory, which causes the segfault).


Some further watches:

priv(m->d.data)->className = 0x0
m->d.data[priv(m->d.data)->className] = "PyQtProxy"

priv(m->d.data)->methodCount = 0x2
priv(m->d.data)->propertyCount = 0x0
priv(m->d.data)->enumeratorCount = 0x0

priv(m->d.data)->methodData = 0xa

priv(m->d.data)->methodData + 5*0 + 4 = 0xe
m->d.data[priv(m->d.data)->methodData + 5*0 + 4] = 0x5 (MethodSignal | 
AccessProtected)
m->d.data[priv(m->d.data)->methodData + 5*0] = 0xb	
m->d.stringdata +  0xb = 0x0a488f4b "ABOUT_TO_SHOW()"

priv(m->d.data)->methodData + 5*1 + 4 = 0x13
m->d.data[priv(m->d.data)->methodData + 5*1 + 4] = SEGFAULT!
m->d.data[priv(m->d.data)->methodData + 5*1] = 0x23
m->d.stringdata + 0x23 = 0x0a488f63 ""


---------------------------------------------------------------

The problem appears to be in qobject.sip:


     // Add the non-string data.
     uint *data = new uint[16];

     for (int d = 0; d < 16; ++d)
         data[d] = staticMetaObject.d.data[d];

     // Fix the changed values;
     data[10] = sig_pos;
     data[11] = args_pos;
     data[14] = 0x05;


but staticMetaObject.d.data is:

static const uint slot_meta_data[] = {
     // content:
     1,       // revision
     0,       // classname
     0,    0, // classinfo
     2,   10, // methods (number, offset in this array of first one)
     0,    0, // properties
     0,    0, // enums/sets

     // signals: signature, parameters, type, tag, flags
     11,   10,   10,   10, 0x05,

     // slots: signature, parameters, type, tag, flags
     35,   10,   10,   10, 0x0a,

     0        // eod
};


which is larger than 16 bytes. My fix is simple:

     // Add the non-string data.
     uint *data = new uint[sizeof(slot_meta_data)];

     for (int d = 0; d < sizeof(slot_meta_data); ++d)
         data[d] = slot_meta_data[d];


and it appears to work.
-- 
Giovanni Bajo





More information about the PyQt mailing list