Qt World Summit: Register Today!

Funky Qt emit/activate bug? Now with MORE information!

  • I have some code. This code, in my Win32 release build only, as built on the production build machine only (i.e. when I build on my local machine, the bug does not exhibit), exhibits a funky bug.

    This call exists:
    @emit pathChanged(path);@
    where path is a QString. In the debugger (which took an age to get sorted, needing to alter the build machine to add debug symbols and make pdb files and all that) at this point I can see it has a nice sensible value.

    This is the next level down in the stack, in a moc_ file (autogenerated)
    @void pathContext::pathChanged(const QString & _t1)const
    void _a[] = { 0, const_cast<void>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(const_cast< pathContext *>(this), &staticMetaObject, 0, _a);

    At this point, as you can see, _a is an array of void pointers, the first one being just a null void pointer, and the second being a pointer-to-QString recast as a void pointer.

    A couple of levels in the stack later (I cannot see into the intermediate levels), we arrive here:

    @void Workplace::MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
    if (_c == QMetaObject::InvokeMetaMethod) {
    MainWindow *_t = static_cast<MainWindow *>(_o);
    switch (_id) {
    case 0: _t->mainWindowStarted(); break;
    case 1: _t->setPath((reinterpret_cast< const QString()>(_a[1]))); break;@

    That setPath is the slot that I connected the signal to. All looks good so far, but there's a problem. Here it crashes. When I look at the value of _a, which is recognised as a void * * in the debugger, it's 0x00000001.

    So it seems to me that the dereference there is case_1 is trying to dereference a pointer to memory location 0x00000001, which predictably causes problems.

    What makes no sense, though, is that:

    1. This is autogenerated code. It leaves me code at the @emit pathChanged(path);@ and path is just a simple QString, so how does something go wrong in the very few following steps.

    2. The first time through this code, everything is fine. It only goes wrong the SECOND time through. Identical input (i.e. same value for path).

    3. Doesn't exhibit in debug versions, or 64 bit versions, or Linux or Solaris versions, or any version except the 32 bit Win release version as built on the build machine.

    I can't come up with any sensible ideas for what would cause such an odd Heisenbug (although Heisenbug no more now that I can reproduce it, if only by hijacking the production build machine).

    Does anyone have any ideas? I'm trying to see what the value of _a is at that point when it doesn't crash, but this debug setup is all held together with string at the moment, just to see this.

  • Addendum: When I very naughtily break it at the case_1 statement, and check the value of a_ and find it to be 0×00000001, if i manually change that value to match the value of _a in the activate statement in the previous code, it works; so I'm comnig around to the conclusion that something in QT is trashing that value, but only the SECOND time through this signal/slot sequence.

    This makes no sense to me :(

  • This is quite deep inside of your code. It will be hard for anyone to make the right suggestion.
    However, while through your post a question popped up. Did perform a rerun of qmake and a complete rebuild on the machine with the problem?
    Out of personal experience, this helps quite often.

  • It is ridiculously deep inside my code; so deep, it leaves my code at the top there and burrows into QT :p

    I might well request a QT rebuild on the Win32 build machines.

  • I've dug a lot deeper (and had the Win32 QT libs rebuilt, in release, but with debugging symbols added). Maybe I have enough now that someone can shed some light on this and help me out.

    Way deep in qobject.cpp is this function:

    @void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv)@

    That argv has a non-zero value. Ultimately, when it's working, many lines later, is this call (in a do-while loop):

    @callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);@

    Clearly, if argv is non-zero (i.e. we have a parameter), than the intent is to get that parameter to the function we're going to call. So far, so good. Sometimes, however, that argv value (which was a sensible value at the start of the function QMetaObject::activate) has become 0x00000001 at this point.

    I have found the line of code that changes argv from a sensible value to this bad value; still inside QMetaObject::activate, way down at line 3557 in the version of the code I'm using (about 140 lines into the function in the version of the code I'm using)

    @if (receiverInSameThread)
    QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);@

    This changes the value of argv (or at least, when I put a breakpoint before this line, argv is good, and when I have a breakpoint after this line, argv is bad), and when the do-while loop repeats, disaster.

    I've got no idea what this code is all about. I have recently spotted that the slot being called throws an exception; the cycle from a higher level is signal calls slot, slot throws exception, everything carries on, user repeats exactly the same, signal calls slot, and then this argv being changed issue leading to a segFault. I recall that calling exceptions (disclaimer; I'm the maintainer and new developer, not the original writer, so I'm not 100% sure what's happening anywhere in this code) from within slots is potentially problematic. Could that be related?

  • Lifetime Qt Champion


    AFAIK, throwing exceptions from a slot is not supported and IIRC you also need to have a build of Qt with exceptions enabled to use them (BUT that doesn't mean it's getting supported in slots). There's the "Exception Safety" chapter in the documentation about that.

    I would recommend you (if possible) to get rid of exceptions. You can also search the development mailing list archive, there was a discussion about exception recently

Log in to reply