Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.2.1, 5.3.1
-
None
-
9e71faae038de4c41c206f1321da1b37ab6ca8b1 (qtdeclarative)
Description
Logic inside QQmlBinding::createBinding expect the typeData to have been previously cached:
QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
But this may not be the case depending on how data has been loaded.
For example, QQmlComponent::setData executes:
QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.getType(data, url);
This variant of QQmlTypeLoader::getType does not cache the typeData:
QQmlTypeData *typeData = new QQmlTypeData(url, this);
QQmlDataLoader::loadWithStaticData(typeData, data);
return typeData;
As a side effect, any components loaded via setData (useful if the component text is in memory) crash while trying to do trivial bindings.
As a reference, I'm attaching in test.qml some simple content that crashes on page.state = "down" if loaded via setData. The crash happens when clicking on the red square, and looks like:
2014/09/08 17:32:16 qglobal.cpp:2104: ASSERT failure in QVector<T>::operator[]: "index out of range", file /home/niemeyer/src/tmp/qt5/qtbase/include/QtCore/../../src/corelib/tools
/qvector.h, line 369Program received signal SIGABRT, Aborted.
0x00007ffff4a88f89 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 0x00007ffff4a88f89 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1 0x00007ffff4a8c398 in __GI_abort () at abort.c:89
#2 0x00007ffff52e80b6 in qt_message_fatal (context=..., message=...) at global/qlogging.cpp:979
#3 0x00007ffff52e5c9e in QMessageLogger::fatal (this=0x7fffffffc2f0, msg=0x7ffff5630340 "ASSERT failure in %s: \"%s\", file %s, line %d") at global/qlogging.cpp:384
#4 0x00007ffff52e182b in qt_assert_x (where=0x7ffff5e63f36 "QVector<T>::operator[]", what=0x7ffff5e63f23 "index out of range",
file=0x7ffff5e63ed0 "/home/niemeyer/src/tmp/qt5/qtbase/include/QtCore/../../src/corelib/tools/qvector.h", line=369) at global/qglobal.cpp:2104
#5 0x00007ffff5b3fcf3 in QVector<QV4::Function*>::operator[] (this=0x7fffc4048948, i=2) at /home/niemeyer/src/tmp/qt5/qtbase/include/QtCore/../../src/corelib/tools/qvector.h:369
#6 0x00007ffff5dccf42 in QQmlBinding::createBinding (id=0, obj=0xb564d0, ctxt=0xd2f380, url=..., lineNumber=9) at qml/qqmlbinding.cpp:94
#7 0x00007ffff6b29b91 in QQuickPropertyChanges::actions (this=0x202c9a0) at util/qquickpropertychanges.cpp:482
#8 0x00007ffff6b20de2 in QQuickStatePrivate::generateActionList (this=0xb56370) at util/qquickstate.cpp:340
#9 0x00007ffff6b21c88 in QQuickState::apply (this=0xb562c0, trans=0x0, revert=0xb5fd30) at util/qquickstate.cpp:579
(... etc ...)
To make sure this was indeed the issue, I changed the getType for the static data with the following patch, and it worked fine:
— a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1552,8 +1552,15 @@ QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url)
{
LockHolder<QQmlTypeLoader> holder(this);
- QQmlTypeData *typeData = new QQmlTypeData(url, this);
- QQmlDataLoader::loadWithStaticData(typeData, data);
+ QQmlTypeData *typeData = m_typeCache.value(url);
+
+ if (!typeData) {{
+ typeData = new QQmlTypeData(url, this);
+ m_typeCache.insert(url, typeData);
+ QQmlDataLoader::loadWithStaticData(typeData, data);
+ }}
+
+ typeData->addref();return typeData;
}
Ideally the type data would not be referenced via a URL like that, but someone more experienced with the logic will be able to tell what the proper fix is.