Crash when loading a QML for the second time
-
Hi,
I'm building a Qt application (Qt 5.15) and, in one dialog, I create a popup QML window to enter a wifi key. The first time it works as expected but, when I close the popup and click again in a SSID from the list to open it again, the application crashes with the warning:QQmlEngine::setContextForObject(): Object already has a QQmlContext
It only crashes on Linux, on Windows it doesn't.
This is the constructor of the dialog that loads the QML:
WifiEnterKeyDialog::WifiEnterKeyDialog(QWidget *parent, QString ssid) : QDialog(parent), ui(new Ui::WifiEnterKeyDialog), ssid(ssid) { WifiEnterKeyDialog::parent = parent; ui->setupUi(this); this->setStyleSheet("background-color: white;"); this->resize(850,420); this->setWindowFlag(Qt::FramelessWindowHint, true); this->setModal(true); this->setAttribute(Qt::WA_DeleteOnClose, true); // Ensure the previous QQuickWidget is properly cleaned up if (qw_keyboard) { qw_keyboard->rootContext()->setContextObject(nullptr); delete qw_keyboard; } qw_keyboard = new QQuickWidget(this); // qw_keyboard->rootContext()->setContextObject(nullptr); qw_keyboard->setResizeMode(QQuickWidget::SizeRootObjectToView); // qw_keyboard->rootContext()->engine()->clearComponentCache(); qw_keyboard->rootContext()->setContextProperty("classEnterKeyDialog", this); qw_keyboard->setSource(QUrl(QStringLiteral("qrc:/inputkey2.qml"))); qw_keyboard->setGeometry(0, 0, 850, 420); }
This is how I create the dialog:
void WifiDialog::onLwNetworkSelected(QListWidgetItem *current) { qDebug() << "SSID: " << current->text(); wifi_enter_key = new WifiEnterKeyDialog(this, current->text()); wifi_enter_key->show(); }
And this is the qml file:
import QtQuick 2.15 import QtQuick.VirtualKeyboard 1.0 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.3 Rectangle { id: rect ColumnLayout { id: columnLayout width: rect.width Button { id: exit_button Layout.alignment: Qt.AlignRight Layout.rightMargin: 3 Layout.topMargin: 3 Layout.minimumHeight: 10 Layout.minimumWidth: 10 icon.source: "qrc:/Resources/xmark-solid.png" background: Rectangle {color: "white"} onClicked: { wifiKey.text = "" classEnterKeyDialog.closeDialog() } } TextField { id: wifiKey Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 40 Layout.leftMargin: 70 Layout.rightMargin: 70 placeholderText: qsTr("Introducir contraseña") font.family: "Roboto" font.pointSize: 20 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter background: Rectangle { color: "white" border.color: "black" } onTextChanged: { classEnterKeyDialog.setKey(text); } } Button { id: connect_button Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 40 Layout.leftMargin: 70 Layout.rightMargin: 70 Layout.topMargin: 00 Layout.bottomMargin: 0 contentItem: Text { text: qsTr("Conectar") font.family: "Roboto" font.pointSize: 20 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight } background: Rectangle {color: "#8EC31B"} onClicked: { classEnterKeyDialog.connect() wifiKey.text = "" } } Label { id: dummyLabel Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 2480 Layout.topMargin: 20 background: Rectangle { color: "red" } } } InputPanel { id: inputPanel y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height anchors.left: parent.left anchors.right: parent.right } }
I don't understand what is happening and I haven't found any solution. I've tried to call to clearComponentCache() before set the contex property but the crash is still happening (only in Linux)
I've been stuck with this several days. Any help will be appreciated!
Thanks
-
Hi,
I'm building a Qt application (Qt 5.15) and, in one dialog, I create a popup QML window to enter a wifi key. The first time it works as expected but, when I close the popup and click again in a SSID from the list to open it again, the application crashes with the warning:QQmlEngine::setContextForObject(): Object already has a QQmlContext
It only crashes on Linux, on Windows it doesn't.
This is the constructor of the dialog that loads the QML:
WifiEnterKeyDialog::WifiEnterKeyDialog(QWidget *parent, QString ssid) : QDialog(parent), ui(new Ui::WifiEnterKeyDialog), ssid(ssid) { WifiEnterKeyDialog::parent = parent; ui->setupUi(this); this->setStyleSheet("background-color: white;"); this->resize(850,420); this->setWindowFlag(Qt::FramelessWindowHint, true); this->setModal(true); this->setAttribute(Qt::WA_DeleteOnClose, true); // Ensure the previous QQuickWidget is properly cleaned up if (qw_keyboard) { qw_keyboard->rootContext()->setContextObject(nullptr); delete qw_keyboard; } qw_keyboard = new QQuickWidget(this); // qw_keyboard->rootContext()->setContextObject(nullptr); qw_keyboard->setResizeMode(QQuickWidget::SizeRootObjectToView); // qw_keyboard->rootContext()->engine()->clearComponentCache(); qw_keyboard->rootContext()->setContextProperty("classEnterKeyDialog", this); qw_keyboard->setSource(QUrl(QStringLiteral("qrc:/inputkey2.qml"))); qw_keyboard->setGeometry(0, 0, 850, 420); }
This is how I create the dialog:
void WifiDialog::onLwNetworkSelected(QListWidgetItem *current) { qDebug() << "SSID: " << current->text(); wifi_enter_key = new WifiEnterKeyDialog(this, current->text()); wifi_enter_key->show(); }
And this is the qml file:
import QtQuick 2.15 import QtQuick.VirtualKeyboard 1.0 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.3 Rectangle { id: rect ColumnLayout { id: columnLayout width: rect.width Button { id: exit_button Layout.alignment: Qt.AlignRight Layout.rightMargin: 3 Layout.topMargin: 3 Layout.minimumHeight: 10 Layout.minimumWidth: 10 icon.source: "qrc:/Resources/xmark-solid.png" background: Rectangle {color: "white"} onClicked: { wifiKey.text = "" classEnterKeyDialog.closeDialog() } } TextField { id: wifiKey Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 40 Layout.leftMargin: 70 Layout.rightMargin: 70 placeholderText: qsTr("Introducir contraseña") font.family: "Roboto" font.pointSize: 20 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter background: Rectangle { color: "white" border.color: "black" } onTextChanged: { classEnterKeyDialog.setKey(text); } } Button { id: connect_button Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 40 Layout.leftMargin: 70 Layout.rightMargin: 70 Layout.topMargin: 00 Layout.bottomMargin: 0 contentItem: Text { text: qsTr("Conectar") font.family: "Roboto" font.pointSize: 20 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight } background: Rectangle {color: "#8EC31B"} onClicked: { classEnterKeyDialog.connect() wifiKey.text = "" } } Label { id: dummyLabel Layout.alignment: Qt.AlignHCenter Layout.fillWidth: parent Layout.minimumHeight: 2480 Layout.topMargin: 20 background: Rectangle { color: "red" } } } InputPanel { id: inputPanel y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height anchors.left: parent.left anchors.right: parent.right } }
I don't understand what is happening and I haven't found any solution. I've tried to call to clearComponentCache() before set the contex property but the crash is still happening (only in Linux)
I've been stuck with this several days. Any help will be appreciated!
Thanks
@occam25 said in Crash when loading a QML for the second time:
Hi,
Hi,
I'm going to first of all propose what your namesake's (I'm presuming) legacy suggests: Remove everything unnecessary, ie not involved in triggering the problem. Whatever remains is probably responsible. If not, at least it reduces the size of the hay stack.
I'm building a Qt application (Qt 5.15) and, in one dialog, I create a popup QML window to enter a wifi key. The first time it works as expected but, when I close the popup and click again in a SSID from the list to open it again, the application crashes with the warning:
Have you tried running under a debugger, or examining a resulting core dump?
This is the constructor of the dialog that loads the QML:
WifiEnterKeyDialog::WifiEnterKeyDialog(QWidget *parent, QString ssid) : QDialog(parent), ui(new Ui::WifiEnterKeyDialog), ssid(ssid) {
[...]
// Ensure the previous QQuickWidget is properly cleaned up if (qw_keyboard) {
Is qw_keyboard a member variable, global or thread_local, or something else? Is it explicitly initialized to nullptr or something else evaluating to
false
?This is how I create the dialog:
void WifiDialog::onLwNetworkSelected(QListWidgetItem *current) { qDebug() << "SSID: " << current->text();
An example of excess: for the sake of the razor, please trim the debug output and commented-out statements for forum use. Unless used in triggering the crash or discussion of the output, it's more overhead to read.
And this is the qml file:
More razor feed. If it's not important, cut it. Maybe some of this is important. I stopped reading when it got into margin sizing.
I don't understand what is happening and I haven't found any solution. I've tried to call to clearComponentCache() before set the contex property but the crash is still happening (only in Linux)
On one hand, congratulations on having a theory. Many people give up at "it doesn't work". On the other, why was this theory chosen? The component cache belongs to the QML engine. The QQuickWidget isn't being passed an engine, meaning that it creates its own. Similarly with the context property, each engine has it's own root.
I've been stuck with this several days. Any help will be appreciated!
Hopefully I'm coming across as direct rather than harsh. You've identified a problem, and done some work to isolate it. That's a big step. Let's refine it to a point.
-
@occam25 said in Crash when loading a QML for the second time:
Hi,
Hi,
I'm going to first of all propose what your namesake's (I'm presuming) legacy suggests: Remove everything unnecessary, ie not involved in triggering the problem. Whatever remains is probably responsible. If not, at least it reduces the size of the hay stack.
I'm building a Qt application (Qt 5.15) and, in one dialog, I create a popup QML window to enter a wifi key. The first time it works as expected but, when I close the popup and click again in a SSID from the list to open it again, the application crashes with the warning:
Have you tried running under a debugger, or examining a resulting core dump?
This is the constructor of the dialog that loads the QML:
WifiEnterKeyDialog::WifiEnterKeyDialog(QWidget *parent, QString ssid) : QDialog(parent), ui(new Ui::WifiEnterKeyDialog), ssid(ssid) {
[...]
// Ensure the previous QQuickWidget is properly cleaned up if (qw_keyboard) {
Is qw_keyboard a member variable, global or thread_local, or something else? Is it explicitly initialized to nullptr or something else evaluating to
false
?This is how I create the dialog:
void WifiDialog::onLwNetworkSelected(QListWidgetItem *current) { qDebug() << "SSID: " << current->text();
An example of excess: for the sake of the razor, please trim the debug output and commented-out statements for forum use. Unless used in triggering the crash or discussion of the output, it's more overhead to read.
And this is the qml file:
More razor feed. If it's not important, cut it. Maybe some of this is important. I stopped reading when it got into margin sizing.
I don't understand what is happening and I haven't found any solution. I've tried to call to clearComponentCache() before set the contex property but the crash is still happening (only in Linux)
On one hand, congratulations on having a theory. Many people give up at "it doesn't work". On the other, why was this theory chosen? The component cache belongs to the QML engine. The QQuickWidget isn't being passed an engine, meaning that it creates its own. Similarly with the context property, each engine has it's own root.
I've been stuck with this several days. Any help will be appreciated!
Hopefully I'm coming across as direct rather than harsh. You've identified a problem, and done some work to isolate it. That's a big step. Let's refine it to a point.
@jeremy_k said in Crash when loading a QML for the second time:
Have you tried running under a debugger, or examining a resulting core dump?
I cross-compiled and run valgrind to try to find where the crash happens, this is the relevant output:
==934== Thread 1: ==934== Invalid read of size 8 ==934== at 0x5C8CC14: QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(QQmlType const&) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B8AC2B: QV4::QQmlContextWrapper::getPropertyAndBase(QV4::QQmlContextWrapper const*, QV4::PropertyKey, QV4::Value const*, bool*, QV4::Value*, QV4::Lookup*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B8AF6F: QV4::QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(QV4::Lookup*, QV4::ExecutionEngine*, QV4::Value*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5BCEF87: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5BD1E4B: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B656F3: QV4::Function::call(QV4::Value const*, QV4::Value const*, int, QV4::ExecutionContext const*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5CFC0AB: QQmlJavaScriptExpression::evaluate(QV4::CallData*, bool*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D03047: QQmlBinding::evaluate(bool*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D070A3: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D04F47: QQmlBinding::update(QFlags<QQmlPropertyData::WriteFlag>) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D12F93: QQmlObjectCreator::finalize(QQmlInstantiationInterrupt&) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5C9B26F: QQmlComponentPrivate::complete(QQmlEnginePrivate*, QQmlComponentPrivate::ConstructionState*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== Address 0xbaadad8 is 8 bytes inside a block of size 24 free'd ==934== at 0x48688C8: operator delete(void*, unsigned long) (vg_replace_malloc.c:935) ==934== by 0x5C8C5DB: QQmlEngine::~QQmlEngine() (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5C8C6D7: QQmlEngine::~QQmlEngine() (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x6407D1B: QObjectPrivate::deleteChildren() (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x4ACD87B: QWidget::~QWidget() (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x48BA537: QQuickWidget::~QQuickWidget() (in /usr/lib/libQt5QuickWidgets.so.5.15.9) ==934== by 0x1C692F: WifiEnterKeyDialog::~WifiEnterKeyDialog() (wifienterkeydialog.cpp:75) ==934== by 0x1C6A57: WifiEnterKeyDialog::~WifiEnterKeyDialog() (wifienterkeydialog.cpp:78) ==934== by 0x640A81F: QObject::event(QEvent*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x4A8C0EF: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x63D7B07: QCoreApplication::notifyInternal2(QObject*, QEvent*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x63DB12F: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== Block was alloc'd at ==934== at 0x4865CFC: operator new(unsigned long) (vg_replace_malloc.c:422) ==934== by 0xBAC5D53: VirtualKeyboardInputContextPrivate::VirtualKeyboardInputContextPrivate() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0xBAC6CBF: VirtualKeyboardInputContext::VirtualKeyboardInputContext() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0xBAC6ECF: VirtualKeyboardInputContext::instance() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0x5474A8B: QPlatformInputContextFactory::create(QString const&) (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x5474D27: QPlatformInputContextFactory::create() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0xB11AEFB: ??? (in /usr/lib/plugins/platforms/libqlinuxfb.so) ==934== by 0x548A4AF: QGuiApplicationPrivate::eventDispatcherReady() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x63DF0FB: QCoreApplicationPrivate::init() (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x548D81B: QGuiApplicationPrivate::init() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x4A92047: QApplicationPrivate::init() (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x12DD0F: main (main.cpp:51)
As you can see, when the WifiEnterKeyDialog is closed the first time, its destructor is called and the QQmlEngine is removed. Then, when the user selects a network again, a new WifiEnterKeyDialog is created and during the QML load/initialization, QQmlEnginePrivate is called and tries to access something that was previously deleted when the first WifiEnterKeyDialog instance was removed. Whatever wrong memory is accessed was allocated in the VirtualKeyboardInputContextPrivate constructor that is a free virtual keyboard implementation. Maybe there is a way to reload the virtualkeyboard to create the QQmlEngine again if it doesn’t exist anymore? I have very little experience with QML.
Is qw_keyboard a member variable, global or thread_local, or something else? Is it explicitly initialized to nullptr or something else evaluating to
false
?It is a member variable initialized to NULL. This was added as part of the many things I tried to solve the issue, after looking at valgrind's output this is useless.
An example of excess: for the sake of the razor, please trim the debug output and commented-out statements for forum use. Unless used in triggering the crash or discussion of the output, it's more overhead to read.
And this is the qml file:
More razor feed. If it's not important, cut it. Maybe some of this is important. I stopped reading when it got into margin sizing.
Fair enough. I actually removed many other comments but missed that one. About the qml file.. since I'm new to QML I was unsure what parts were relevant or not, but I will take this into account in future post, I promise!
On one hand, congratulations on having a theory. Many people give up at "it doesn't work". On the other, why was this theory chosen? The component cache belongs to the QML engine. The QQuickWidget isn't being passed an engine, meaning that it creates its own. Similarly with the context property, each engine has it's own root.
I saw that the crash was happening when setting the qml source so I thought that it was related with having something fishy in the QML engine, that's why I tried to clean it.
Hopefully I'm coming across as direct rather than harsh. You've identified a problem, and done some work to isolate it. That's a big step. Let's refine it to a point.
I appreciate the direct approach! I'm new to Qt/QML and to this forum so, any input about how to do the things right is welcome.
Thanks for the help
-
@jeremy_k said in Crash when loading a QML for the second time:
Have you tried running under a debugger, or examining a resulting core dump?
I cross-compiled and run valgrind to try to find where the crash happens, this is the relevant output:
==934== Thread 1: ==934== Invalid read of size 8 ==934== at 0x5C8CC14: QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(QQmlType const&) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B8AC2B: QV4::QQmlContextWrapper::getPropertyAndBase(QV4::QQmlContextWrapper const*, QV4::PropertyKey, QV4::Value const*, bool*, QV4::Value*, QV4::Lookup*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B8AF6F: QV4::QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(QV4::Lookup*, QV4::ExecutionEngine*, QV4::Value*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5BCEF87: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5BD1E4B: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5B656F3: QV4::Function::call(QV4::Value const*, QV4::Value const*, int, QV4::ExecutionContext const*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5CFC0AB: QQmlJavaScriptExpression::evaluate(QV4::CallData*, bool*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D03047: QQmlBinding::evaluate(bool*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D070A3: ??? (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D04F47: QQmlBinding::update(QFlags<QQmlPropertyData::WriteFlag>) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5D12F93: QQmlObjectCreator::finalize(QQmlInstantiationInterrupt&) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5C9B26F: QQmlComponentPrivate::complete(QQmlEnginePrivate*, QQmlComponentPrivate::ConstructionState*) (in /usr/lib/libQt5Qml.so.5.15.9) ==934== Address 0xbaadad8 is 8 bytes inside a block of size 24 free'd ==934== at 0x48688C8: operator delete(void*, unsigned long) (vg_replace_malloc.c:935) ==934== by 0x5C8C5DB: QQmlEngine::~QQmlEngine() (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x5C8C6D7: QQmlEngine::~QQmlEngine() (in /usr/lib/libQt5Qml.so.5.15.9) ==934== by 0x6407D1B: QObjectPrivate::deleteChildren() (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x4ACD87B: QWidget::~QWidget() (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x48BA537: QQuickWidget::~QQuickWidget() (in /usr/lib/libQt5QuickWidgets.so.5.15.9) ==934== by 0x1C692F: WifiEnterKeyDialog::~WifiEnterKeyDialog() (wifienterkeydialog.cpp:75) ==934== by 0x1C6A57: WifiEnterKeyDialog::~WifiEnterKeyDialog() (wifienterkeydialog.cpp:78) ==934== by 0x640A81F: QObject::event(QEvent*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x4A8C0EF: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x63D7B07: QCoreApplication::notifyInternal2(QObject*, QEvent*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x63DB12F: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/lib/libQt5Core.so.5.15.9) ==934== Block was alloc'd at ==934== at 0x4865CFC: operator new(unsigned long) (vg_replace_malloc.c:422) ==934== by 0xBAC5D53: VirtualKeyboardInputContextPrivate::VirtualKeyboardInputContextPrivate() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0xBAC6CBF: VirtualKeyboardInputContext::VirtualKeyboardInputContext() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0xBAC6ECF: VirtualKeyboardInputContext::instance() (in /usr/lib/plugins/platforminputcontexts/libVirtualKeyboard.so) ==934== by 0x5474A8B: QPlatformInputContextFactory::create(QString const&) (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x5474D27: QPlatformInputContextFactory::create() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0xB11AEFB: ??? (in /usr/lib/plugins/platforms/libqlinuxfb.so) ==934== by 0x548A4AF: QGuiApplicationPrivate::eventDispatcherReady() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x63DF0FB: QCoreApplicationPrivate::init() (in /usr/lib/libQt5Core.so.5.15.9) ==934== by 0x548D81B: QGuiApplicationPrivate::init() (in /usr/lib/libQt5Gui.so.5.15.9) ==934== by 0x4A92047: QApplicationPrivate::init() (in /usr/lib/libQt5Widgets.so.5.15.9) ==934== by 0x12DD0F: main (main.cpp:51)
As you can see, when the WifiEnterKeyDialog is closed the first time, its destructor is called and the QQmlEngine is removed. Then, when the user selects a network again, a new WifiEnterKeyDialog is created and during the QML load/initialization, QQmlEnginePrivate is called and tries to access something that was previously deleted when the first WifiEnterKeyDialog instance was removed. Whatever wrong memory is accessed was allocated in the VirtualKeyboardInputContextPrivate constructor that is a free virtual keyboard implementation. Maybe there is a way to reload the virtualkeyboard to create the QQmlEngine again if it doesn’t exist anymore? I have very little experience with QML.
Is qw_keyboard a member variable, global or thread_local, or something else? Is it explicitly initialized to nullptr or something else evaluating to
false
?It is a member variable initialized to NULL. This was added as part of the many things I tried to solve the issue, after looking at valgrind's output this is useless.
An example of excess: for the sake of the razor, please trim the debug output and commented-out statements for forum use. Unless used in triggering the crash or discussion of the output, it's more overhead to read.
And this is the qml file:
More razor feed. If it's not important, cut it. Maybe some of this is important. I stopped reading when it got into margin sizing.
Fair enough. I actually removed many other comments but missed that one. About the qml file.. since I'm new to QML I was unsure what parts were relevant or not, but I will take this into account in future post, I promise!
On one hand, congratulations on having a theory. Many people give up at "it doesn't work". On the other, why was this theory chosen? The component cache belongs to the QML engine. The QQuickWidget isn't being passed an engine, meaning that it creates its own. Similarly with the context property, each engine has it's own root.
I saw that the crash was happening when setting the qml source so I thought that it was related with having something fishy in the QML engine, that's why I tried to clean it.
Hopefully I'm coming across as direct rather than harsh. You've identified a problem, and done some work to isolate it. That's a big step. Let's refine it to a point.
I appreciate the direct approach! I'm new to Qt/QML and to this forum so, any input about how to do the things right is welcome.
Thanks for the help
@occam25 said in Crash when loading a QML for the second time:
@jeremy_k said in Crash when loading a QML for the second time:
==934== Thread 1: ==934== Invalid read of size 8 ==934== at 0x5C8CC14: QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(QQmlType const&) (in /usr/lib/libQt5Qml.so.5.15.9)
Is there an attempt to share a singleton instance between multiple engines? For QObject singletons, the instance can be owned by the engine or externally. Objects owned by the engine are deleted on engine destruction, which could lead to a similar crash. I'm not sure how QJSValue singleton ownership works. > As you can see, when the WifiEnterKeyDialog is closed the first time, its destructor is called and the QQmlEngine is removed. Then, when the user selects a network again, a new WifiEnterKeyDialog is created and during the QML load/initialization, QQmlEnginePrivate is called and tries to access something that was previously deleted when the first WifiEnterKeyDialog instance was removed. Whatever wrong memory is accessed was allocated in the VirtualKeyboardInputContextPrivate constructor that is a free virtual keyboard implementation. Maybe there is a way to reload the virtualkeyboard to create the QQmlEngine again if it doesn’t exist anymore? I have very little experience with QML. How is the first engine created? Is reusing it an option? You've already clarified the qw_keyboard confusion below, but that's the sort of thing I would be looking for. Are there any pointers to objects shared with the first qml engine instance that are not reinitialized when shared with the second. > > > Is qw_keyboard a member variable, global or thread_local, or something else? Is it explicitly initialized to nullptr or something else evaluating to `false`? > > It is a member variable initialized to NULL. This was added as part of the many things I tried to solve the issue, after looking at valgrind's output this is useless. > > > An example of excess: for the sake of the razor, please trim the debug output and commented-out statements for forum use. Unless used in triggering the crash or discussion of the output, it's more overhead to read. > > > > > And this is the qml file: > > > > More razor feed. If it's not important, cut it. Maybe some of this is important. I stopped reading when it got into margin sizing. > > Fair enough. I actually removed many other comments but missed that one. About the qml file.. since I'm new to QML I was unsure what parts were relevant or not, but I will take this into account in future post, I promise! You might benefit from rebuilding a test interface from the ground up with nothing but a TextField and InputPanel.