Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble diagnosing segfault in Qt application

I have an application using QtWebKit. It loads URLs and exports some stats on the render trees. This section of code is causing problems:

...
if (mPage != 0) {
    disconnectSignals(mPage);
    delete mPage;
}
mPage = new Page(); //subclass of QWebPage
connectSignals(mPage);
QNetworkRequest req;
req.setUrl("http://...");
mPage->mainFrame()->load(req, QNetworkAccessManager::GetOperation);

The first time the above code runs mPage=0, the page loads fine, and everything else goes as expected. The second time, it's a pointer to the previously created page, so it gets disconnected and deleted. After load() returns control to the main event loop, I get a SIGSEGV with the following stack trace.

#0  0x00007ffff49a1e56 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)          () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#1  0x00007ffff6842972 in QWebFrame::loadFinished(bool) () from /home/ubuntu/3rdparty/qt-    4.8.1/lib/libQtWebKit.so.4
#2  0x00007ffff6881955 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#3  0x00007ffff6bde3ab in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#4  0x00007ffff6c0ef14 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#5  0x00007ffff6e0183b in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#6  0x00007ffff6e016e8 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#7  0x00007ffff6e01755 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#8  0x00007ffff6e0218c in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#9  0x00007ffff49a20c1 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#10 0x00007ffff4d72b46 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtNetwork.so.4
#11 0x00007ffff4de91c5 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtNetwork.so.4
#12 0x00007ffff49a7286 in QObject::event(QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#13 0x00007ffff5243fa4 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#14 0x00007ffff5248e23 in QApplication::notify(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#15 0x00007ffff498e21c in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#16 0x00007ffff4991aba in QCoreApplicationPrivate::sendPostedEvents(QObject*, int,     QThreadData*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#17 0x00007ffff49bce53 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#18 0x00007ffff235ba5d in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#19 0x00007ffff235c258 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#20 0x00007ffff235c429 in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#21 0x00007ffff49bd27f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#22 0x00007ffff52e78ae in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#23 0x00007ffff498d002 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#24 0x00007ffff498d257 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /   home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#25 0x00007ffff4991db5 in QCoreApplication::exec() () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#26 0x0000000000408ba0 in main (argc=3, argv=<optimized out>) at RenderTreeAnalyzer.cpp:474
like image 767
Kevin Avatar asked Jun 15 '12 02:06

Kevin


2 Answers

You have to schedule mPage for deletion with deleteLater rather than deleting it directly because there may well be undelivered events for your mPage in the event queue.

If control returns to the event loop, Qt tries to access the deleted object which leads to your segmentation fault.

However, from you code example, I did not fully understand why you need the newPage() signal.

From my understanding, mPage->deleteLater() should be sufficient (w.r.t. to avoiding the seg-fault) and you should be able to reassign your local/member variable mPage with a new value (i.e. a pointer to a new Page) immediately.

If you need the old Page to be deleted immediately, it is correct that you need to return to the event loop, because it is only deleted then.

You have several opportunities to trigger the event loop and get you deletion request processed:

  1. Use your queued signal/slot setup
  2. Call QApplication::processEvents(); after calling mPage->deleteLater() to process any events in the event queue.
  3. Call QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); to only process all deferred deletions.
  4. Call QCoreApplication::sendPostedEvents(mPage, QEvent::DeferredDelete); to only process the deferred deletion for mPage.

Disclaimer: I have not explicitly tried these suggesions (at least not recently that I remember), but I checked a lot of Qt's event management source code recently (in addition to the docs, of course), so I am pretty confident that all of them work.

like image 71
Johannes S. Avatar answered Nov 07 '22 22:11

Johannes S.


The issue was delete mPage;. I have to use mPage->deleteLater(); emit getNext(); instead. deleteLater() schedules the object for deletion the next time the program returns to the main event loop. emit getNext(); is connected to a slot that picks back up at mPage = new Page();. Its connection type is Qt::QueuedConnection, so it will yield to the event loop before calling the slot. I'm not exactly sure why, but you have to schedule the deletion and return to the event loop like this to properly close the old signals and set up the new ones.

So, this works, but if someone can tell me what's going on in more detail, I'll accept yours instead. Thanks.

like image 3
Kevin Avatar answered Nov 07 '22 22:11

Kevin