2014-02-11 2 views
5

Примечание: Я также разместил это в списке рассылки PyQt - я отвечу на свой вопрос здесь, если там появится хороший ответ.PyQt: Иногда segfaults при использовании QApplication.quit

У меня возникли проблемы со случайной ошибкой сегментацией при выполнении QApplication.quit(), возможно, связанных с libQt5Network.so и/или QtWebKit.

Прежде всего, 3 тестовых систем я использую:

  • Arch Linux, PyQt 5.2, Qt 5.2.0, Python 3.3.3
  • Ubuntu 13,10, PyQt 5.0.1, Qt 5.0.2, Python 3.3.2 в VM
  • Windows 7, PyQt 5.2, Qt 5.2.0, Python 3.3.3

Эти аварии не произошло на арке для меня до сих пор, довольно часто на Ubuntu, и время от времени в Windows. (Хотя для Windows просто догадки, я просто получить это python.exe не работают больше Foo.)

Оригинал аварии

я первый заметил проблему в большом проекте (GER), qutebrowser, , где он дал мне эту StackTrace при вводе :quit (на Ubuntu):

#0 0xb5c296fc in QMutex::lock()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#1 0xb3bdd97d in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#2 0xb3bdf0d0 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#3 0xb3bd4418 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#4 0xb3bd8b1e in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#5 0xb5dedf10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#6 0xb5dee48b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#7 0xb5e59155 in QIODevice::readyRead()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#8 0xb3bb1f14 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#9 0xb3ba4d99 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#10 0xb3bc03bb in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#11 0xb6483a54 in QApplicationPrivate::notify_helper(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#12 0xb6488e66 in QApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#13 0xb6bb7e80 in sipQApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-33m-i386-linux-gnu.so 
#14 0xb5dc737a in QCoreApplication::notifyInternal(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#15 0xb5e11f67 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#16 0xb5aaf83e in g_main_context_dispatch() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#17 0xb5aafbe8 in ??() from /lib/i386-linux-gnu/libglib-2.0.so.0 
#18 0xb5aafca8 in g_main_context_iteration() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#19 0xb5e1138f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#20 0xb5dc5c06 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#21 0xb5dc6014 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#22 0xb5c2b90b in QThread::exec()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#23 0xb5c2b99b in QThread::run()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#24 0xb5c2fa08 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#25 0xb7774d78 in start_thread (arg=0xa5314b40) at pthread_create.c:311 
#26 0xb76ac01e in clone() at ../sysdeps/unix/sysv/linux/i386/clone.S:131 

Core dump here (15Mb, GZIP).

Пример минимального

Тогда я попробовал еще раз с минимальным примером, который завершает работу сама автоматически после того, как второй с QTimer. Я должен был запустить его в цикле в течение приблизительно минуты или около того, прежде чем это случилось:

from PyQt5.QtCore import QUrl, QTimer 
from PyQt5.QtWidgets import QApplication 
from PyQt5.QtWebKitWidgets import QWebView 

app = QApplication([]) 
wv = QWebView() 
wv.load(QUrl("http://www.heise.de/")) 
t = QTimer() 
t.timeout.connect(QApplication.quit) 
t.start(1000) 
wv.show() 
app.exec_() 

Это дало мне это очень похоже StackTrace (на Ubuntu):

#0 0xb6cfd8d2 in QCoreApplication::postEvent(QObject*, QEvent*, int)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#1 0xb6d21c83 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#2 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#3 0xb3e47935 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#4 0xb3dcf687 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#5 0xb3e483b3 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#6 0xb6d21f10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#7 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#8 0xb3e43fe5 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#9 0xb3d93b1e in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#10 0xb3d94630 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#11 0xb3d9471b in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#12 0xb6d21f10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#13 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#14 0xb6d8d155 in QIODevice::readyRead()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#15 0xb3e09f14 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#16 0xb3dfcd99 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#17 0xb3e183bb in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#18 0xb492ba54 in QApplicationPrivate::notify_helper(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#19 0xb4930e66 in QApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#20 0xb505fe80 in sipQApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-33m-i386-linux-gnu.so 
#21 0xb6cfb37a in QCoreApplication::notifyInternal(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#22 0xb6d45f67 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#23 0xb65f483e in g_main_context_dispatch() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#24 0xb65f4be8 in ??() from /lib/i386-linux-gnu/libglib-2.0.so.0 
#25 0xb65f4ca8 in g_main_context_iteration() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#26 0xb6d4536d in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#27 0xb6cf9c06 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#28 0xb6cfa014 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#29 0xb6b5f90b in QThread::exec()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#30 0xb6b5f99b in QThread::run()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#31 0xb6b63a08 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#32 0xb7798d78 in start_thread (arg=0xa7812b40) at pthread_create.c:311 
#33 0xb76d001e in clone() at ../sysdeps/unix/sysv/linux/i386/clone.S:131 

Coredump here (15Mb, GZIP).

У кого-нибудь есть идея, что там происходит? Какая-то магия с вещами - это сбор мусора неправильным образом? Я также пробовал обходные методы * для аналогичных sympthoms на PyQt4, но это не помогло .

* не может найти StackOverflow-ответ, где она была описана - в основном настройки QtWidgets.qApp к экземпляру QApplication перед тем работает exec_() и None впоследствии.

ответ

7

Я работал на ловле в ошибку сегментации PyQt/PySide в течение некоторого времени. В основном я обнаружил, что большинство секгровых ошибок можно обвинить в асинхронном характере библиотеки (так и на нас).

Для вашего точного примера вы подключили сигнал timeout к методу quit. Что может случиться здесь, так это то, что в случае вылета вызывается quit, и когда процесс завершается, внезапно все ссылки на объекты приложения являются недействительными. Но в то время как эта операция происходила, QT цикл событий был все еще запущен, и он попытался получить доступ к QNetworkAccessManager, чтобы отправить другой сигнал, но ссылка на это место памяти уже была недействительной, поэтому произошел segfault.

Что необходимо сделать в этих случаях, заключается в том, что вы реализуете какой-то метод выключения, который гарантирует, что все операции будут остановлены, удалите компоненты, используемые вами в правильном порядке, , а затем , как раз тогда вызов разрешает выход.

Я написал об этой теме более подробно здесь, в том числе безопасного метода отключения для QtWebKit приложений: https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08

+0

Спасибо! Ваш учебник, похоже, полезен и для других будущих проблем. Если у вас есть время, не могли бы вы взглянуть, если моя [его реализация] (http://git.the-compiler.org/qutebrowser/commit/?id=0abb5cf7384c1ccfb2b829cbf26fcc92add08bc6) (для первоначального краха, а не для минимального примера) выглядит разумно? –

+1

приветствую :) Я посмотрел в вашем коде, но я не проверял на самом деле. что, как я уже упоминал в учебнике, также было сказано, что этот метод 'deleteLater' также является асинхронным, так что может случиться так, что ваш метод' shutdown' заканчивается, 'deleteLater' запланирован, и приложение завершает работу, но объекты не удаляются так быстро. Я решил это, подключив сигнал «destroy» к методу, где я проверяю, были ли все компоненты удалены успешно, и только затем разрешить приложению завершить работу – andrean

+0

. Вы правы, я об этом не думал. Я выполнил это (http://git.the-compiler.org/qutebrowser/commit/?id=8c37e1c33a11fdcb26ac985b72fae27e083b158a) и теперь, по крайней мере, в моих (нескольких) тестах, никаких segfaults пока. –

Смежные вопросы