5

注: これは PyQt メーリング リストにも投稿しました。適切な回答が得られた場合は、ここで自分の質問に回答します。

QApplication.quit()libQt5Network.so および/または QtWebkit に関連している可能性があります。

まず、私が使用している 3 つのテスト システム:

  • アーチ Linux、PyQt 5.2、Qt 5.2.0、Python 3.3.3
  • VM 内の Ubuntu 13.10、PyQt 5.0.1、Qt 5.0.2、Python 3.3.2
  • Windows 7、PyQt 5.2、Qt 5.2.0、Python 3.3.3

これらのクラッシュは、これまで Arch で発生したことはなく、Ubuntu で頻繁に発生し、Windows でも時々発生しました。(Windows は推測にすぎませんが、このpython.exe はもう動作していませんfoo です。)

元のクラッシュ

大きな(ger)プロジェクトであるqutebrowserで最初に問題に気付きました。入力時に: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

コア ダンプはこちら(15MB、gzip)。

最小限の例

次に、QTimer で 1 秒後に自動的に終了する最小限の例で再試行しました。それが起こる前に、約1分ほどループで実行する必要がありました:

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_()

これにより、非常によく似たスタックトレースが得られました(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

コアダンプはこちら(15MB、gzip)。

何が問題なのか誰にもわかりますか?ガベージコレクションが間違った方法で行われるという魔法はありますか? また、PyQt4 で同様の症状に対していくつかの回避策*を試しましたが、それも役に立ちませんでした。

* 説明されている StackOverflow-answer が見つかりません。基本的には、実行前にインスタンスに設定QtWidgets.qAppし、その後に設定します。QApplicationexec_()None

4

1 に答える 1

8

私はかなり長い間、 PyQt / PySideでセグメンテーション違反をキャッチすることに取り組んできました。基本的に、セグメンテーション違反のほとんどは、ライブラリの非同期の性質に起因する可能性があることがわかりました(したがって、私たちにもあります)。

正確な例では、timeoutシグナルをquitメソッドに接続しました。ここで発生する可能性があるのは、timeoutが発生した場合にquitが呼び出され、プロセスが終了すると、アプリケーションのオブジェクトへのすべての参照が突然無効になることです。しかし、この操作が行われている間、QTのイベントループはまだ実行中であり、別のシグナルをディスパッチするためにそれにアクセスしようとしましQNetworkAccessManagerたが、そのメモリ位置への参照はすでに無効であったため、segfault が発生しました。

これらの場合に行う必要があるのは、一種のシャットダウン メソッドを実装することです。これにより、すべての操作が確実に停止され、使用中のQTコンポーネントが正しい順序で削除され、その後、allow が呼び出されます。終了します。

この件については、QtWebKitアプリの安全なシャットダウン方法を含め、こちらで詳しく説明しています: https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08

于 2014-02-15T08:21:38.780 に答える