Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when launching app using QQmlApplicationEngine from PyQt5 #63

Open
estan opened this issue Apr 28, 2016 · 8 comments
Open

Crash when launching app using QQmlApplicationEngine from PyQt5 #63

estan opened this issue Apr 28, 2016 · 8 comments

Comments

@estan
Copy link

estan commented Apr 28, 2016

I get a segmentation fault if I launch a QML application that makes use of the Python component by using QQmlApplicationEngine from a PyQt5 application. The same does not happen if I launch it from the equivalent C++ application.

Minimal test case:

test.py - The Python launcher application:

from sys import argv, exit

from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine

app = None

def main():
    global app

    app = QGuiApplication(argv)

    engine = QQmlApplicationEngine()
    engine.load('test.qml')

    exit(app.exec_())

if __name__ == '__main__':
    main()

test.cpp - Same as above, but this time in C++:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("test.qml")));

    return app.exec();
}

test.pro - To build main.cpp:

TEMPLATE = app
QT += qml quick
SOURCES += test.cpp

test.qml - The test QML application:

import QtQuick 2.4
import QtQuick.Window 2.2

import io.thp.pyotherside 1.4

Window {
    width: 500
    height: 500
    visible: true

    Python {
    }
}

Launching using C++ ⇒ OK

This works fine, the window is shown and there's no crash:

estan@newton:~/test$ qmake
estan@newton:~/test$ make
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtQuick -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtQml -isystem /usr/include/x86_64-linux-gnu/qt5/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64 -o test.o test.cpp
g++ -m64 -Wl,-O1 -o test test.o   -L/usr/X11R6/lib64 -lQt5Quick -lQt5Gui -lQt5Qml -lQt5Network -lQt5Core -lGL -lpthread 
estan@newton:~/test$ ./test 
estan@newton:~/test$

Launching using Python ⇒ CRASH

This gives a segmentation fault:

estan@newton:~/test$ python3 test.py 
Segmentation fault (core dumped)
estan@newton:~/test$

The backtrace is:

estan@newton:~/test$ gdb python3
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from python3...Reading symbols from /usr/lib/debug//usr/bin/python3.4m...done.
done.
(gdb) run test.py
Starting program: /usr/bin/python3 test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffeb420700 (LWP 29546)]
[New Thread 0x7fffded9b700 (LWP 29547)]

Program received signal SIGSEGV, Segmentation fault.
threadstate_getframe.lto_priv.1748 (self=0x0) at ../Python/pystate.c:167
167     ../Python/pystate.c: No such file or directory.
(gdb) bt
#0  threadstate_getframe.lto_priv.1748 (self=0x0) at ../Python/pystate.c:167
#1  0x00000000004ffdf8 in PyEval_GetFrame () at ../Python/ceval.c:4052
#2  PyEval_GetGlobals () at ../Python/ceval.c:4040
#3  PyImport_Import () at ../Python/import.c:1814
#4  0x00000000005000ff in PyImport_ImportModule () at ../Python/import.c:1313
#5  0x00007fffdd7308d3 in QPythonPriv::QPythonPriv() () from /usr/lib/x86_64-linux-gnu/qt5/qml/io/thp/pyotherside/libpyothersideplugin.so
#6  0x00007fffdd726f75 in QPython::QPython(QObject*, int, int) () from /usr/lib/x86_64-linux-gnu/qt5/qml/io/thp/pyotherside/libpyothersideplugin.so
#7  0x00007fffdd7211aa in void QQmlPrivate::createInto<QPython14>(void*) () from /usr/lib/x86_64-linux-gnu/qt5/qml/io/thp/pyotherside/libpyothersideplugin.so
#8  0x00007fffeef7efdb in QQmlType::create() const () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#9  0x00007fffeefe06c4 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#10 0x00007fffeefe2ac3 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#11 0x00007fffeefe2d58 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#12 0x00007fffeefdf2fa in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#13 0x00007fffeefdfc5a in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#14 0x00007fffeefe115f in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#15 0x00007fffeef69365 in QQmlComponentPrivate::beginCreate(QQmlContextData*) () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#16 0x00007fffeef66fcf in QQmlComponent::create(QQmlContext*) () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#17 0x00007fffeefd43b2 in QQmlApplicationEnginePrivate::_q_finishLoad(QObject*) () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#18 0x00007fffeefd45e2 in QQmlApplicationEnginePrivate::startLoad(QUrl const&, QByteArray const&, bool) () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#19 0x00007fffeefd47c0 in QQmlApplicationEngine::load(QString const&) () from /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
#20 0x00007fffef17ae2e in ?? () from /usr/lib/python3/dist-packages/PyQt5/QtQml.cpython-34m-x86_64-linux-gnu.so
#21 0x0000000000511a1a in call_function (oparg=<optimized out>, pp_stack=0x7fffffffd7e0) at ../Python/ceval.c:4237
#22 PyEval_EvalFrameEx () at ../Python/ceval.c:2838
#23 0x0000000000515c2f in fast_function (nk=<optimized out>, na=<optimized out>, n=<optimized out>, pp_stack=0x7fffffffd8e0, func=<optimized out>) at ../Python/ceval.c:4334
#24 call_function (oparg=<optimized out>, pp_stack=0x7fffffffd8e0) at ../Python/ceval.c:4262
#25 PyEval_EvalFrameEx () at ../Python/ceval.c:2838
#26 0x0000000000519757 in PyEval_EvalCodeEx () at ../Python/ceval.c:3588
#27 0x00000000005ee4cb in PyEval_EvalCode (co=<optimized out>, globals=<optimized out>, locals=<optimized out>) at ../Python/ceval.c:775
#28 0x00000000005f7452 in run_mod () at ../Python/pythonrun.c:2175
#29 0x00000000005f958a in PyRun_FileExFlags () at ../Python/pythonrun.c:2128
#30 0x00000000005f9d3d in PyRun_SimpleFileExFlags () at ../Python/pythonrun.c:1601
#31 0x0000000000619235 in run_file (p_cf=0x7fffffffdb40, filename=<optimized out>, fp=0xaca070) at ../Modules/main.c:319
#32 Py_Main () at ../Modules/main.c:751
#33 0x00000000004c27df in main () at ../Modules/python.c:69
#34 0x00007ffff7811a40 in __libc_start_main (main=0x4c2700 <main>, argc=2, argv=0x7fffffffdd58, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdd48) at libc-start.c:289
#35 0x00000000005bdf09 in _start ()
(gdb)

If I just remove the Python component, the crash disappears.

Sorry for the lack of symbols in pyotherside (no pyotherside-dbg package on Ubuntu), but I hope the crash should be reproducible from this description.

@estan
Copy link
Author

estan commented Apr 28, 2016

This was with:

  • Qt version 5.5.1
  • Python 3.4.3
  • PyQt 5.4.2
  • pyotherside 1.4.0

all from Ubuntu packages on Kubuntu 15.10 with backports enabled.

@estan
Copy link
Author

estan commented Apr 28, 2016

Perhaps obvious, but the crash does not happen with qmlscene on the .qml directly.

@thp
Copy link
Owner

thp commented Apr 30, 2016

Yeah, so right now PyOtherSide assumes that it "owns" the Python interpreter, and initializes the Python interpreter, etc.. -- if you want to use it with PyQt, you have to modify PyOtherSide to not take ownership of the Python interpreter (and in that case, it won't work from a C++ application).

At least this call you have to remove (among other things, I haven't tested it):

https://github.com/thp/pyotherside/blob/master/src/qpython_priv.cpp#L503

Part of the point of PyOtherSide is that you don't need to load the Python interpreter when your QML UI comes up, and only load Python and its modules asynchronously afterwards -- if you use PyQt (which means you load Python and PyQt before loading Qt and your QML UI), you might just as well only use PyQt's support from QML and not use PyOtherSide.

@estan
Copy link
Author

estan commented Apr 30, 2016

Yes, I guessed the problem was something like this. But is there really no way to modify/improve pyotherside such that it can be used in both scenarios? Is it really a hard either-or situation?

For now I'll just use a Qt C++ "launcher" application to load the QML instead, it's not much of a problem. The reason I tried to convert it to PyQt was that we're a mostly Python shop, we had a dependency on PyQt in other parts of this system anyway (it's a set of applications for controlling a mineral analysis machine), and that with the launcher as a Python script, we wouldn't have to compile anything. So I was just a little surprised that it crashed so hard :)

I know the point of pyotherside you bring up of course, but I would argue that even if I had a mixed PyQt widgets + QML application (where the "main" widgets application loads some QML parts), I could be interested in using pyotherside, since it makes it so convenient to make calls out to Python from the QML side. I think there are use cases for pyotherside where you don't use the QML + pyotherside as the top-level architecture of the app.

Anyway, I'll close this issue if there's really no way to make pyotherside work in both scenarios. And thanks for pyotherside, it works excellent for our HMI GUI.

@estan
Copy link
Author

estan commented Apr 30, 2016

Thinking some more, I guess it's just a CPython limitation that you can't have two interpreters within the same process space without them trampling on each other? If so, then I guess there's nothing to do, short of making pyotherside process based instead of thread based (out of the question).

Maybe a short note could be added to the docs that launching a QML app that uses pyotherside is not supported from a Python process? For dumb people like me for which this is not obvious :)

@thp
Copy link
Owner

thp commented May 1, 2016

Note that you can also use qmlscene for running PyOtherSide applications, which should do the trick for your use case then (no need to compile just a C++ launcher, qmlscene is basically that launcher). Alternatively, newer Qt 5 versions also have the qml command-line utility.

@estan
Copy link
Author

estan commented May 1, 2016

Yep, I know qmlscene also works, though the docs says "The qmlscene utility is meant to be used for testing your QML applications, and not as a launcher in a production environment.". But I know it's very commonly used in production anyway.

Did not know about the new qml tool, thanks!

@fcollonval
Copy link

I ran to this page by having the same problem on a small use case:
https://github.com/fcollonval/matplotlib_qtquick_playground/blob/master/QtQuick_controls_v2/mpl_qtquick2.py

I found out that passing the QApplication as parent to the QQmlApplicationEngine avoid having a
segmentation fault.
app = QGuiApplication(argv)
engine = QQmlApplicationEngine(parent=app)

I still have some messages clearly indicating that some Qt object are not destructed in the right order. But at least it seems to avoid the segmentation fault.

Note : I use PyQt5.6 and Python 3.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants