在Qt应用程序中诊断段错误有问题

时间:2012-06-15 02:43:35

标签: c++ qt segmentation-fault qtwebkit

我有一个使用QtWebKit的应用程序。它加载URL并在渲染树上导出一些统计信息。这段代码导致了问题:

...
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);

第一次上面的代码运行mPage = 0,页面加载正常,其他所有内容都按预期运行。第二次,它是指向先前创建的页面的指针,因此它被断开连接并被删除。在load()将控制返回到主事件循环之后,我得到一个带有以下堆栈跟踪的SIGSEGV。

#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

2 个答案:

答案 0 :(得分:5)

您必须使用mPage安排deleteLater删除而不是直接删除它,因为事件队列中的mPage可能存在未传递的事件。

如果控制返回到事件循环,Qt会尝试访问已删除的对象,这会导致您的分段错误。

但是,从您的代码示例中,我并不完全理解为什么需要newPage()信号。

根据我的理解,mPage->deleteLater()应该足够了(以避免seg-fault)并且你应该能够用一个新值(即一个指针)重新分配你的本地/成员变量mPage。一个新的Page)立即。

如果您需要立即删除旧Page,则需要返回事件循环是正确的,因为它只会被删除。

您有几次机会触发事件循环并处理删除请求:

  1. 使用排队的信号/插槽设置
  2. 在调用QApplication::processEvents();后调用mPage->deleteLater()来处理事件队列中的任何事件。
  3. 调用QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);仅处理所有延迟删除。
  4. 致电QCoreApplication::sendPostedEvents(mPage, QEvent::DeferredDelete);仅处理mPage的延期删除。
  5. 免责声明:我没有明确尝试过这些建议(至少最近没有记得),但我最近检查了很多Qt的事件管理源代码(当然除了文档之外),所以我我非常有信心所有这些都有效。

答案 1 :(得分:3)

问题是delete mPage;。我必须使用mPage->deleteLater(); emit getNext();代替。 deleteLater()在下次程序返回主事件循环时调度对象以进行删除。 emit getNext();已连接到mPage = new Page();处选中的广告位。它的连接类型是Qt :: QueuedConnection,因此在调用插槽之前它将产生事件循环。我不确定为什么,但你必须安排删除并返回到这样的事件循环,以正确关闭旧信号并设置新信号。

所以,这很有效,但是如果有人能够更详细地告诉我发生了什么,我会接受你的。感谢。