diff options
author | Matthew Vogt <matthew.vogt@nokia.com> | 2012-05-21 13:40:22 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-05-21 11:22:43 +0200 |
commit | f16f4c3b78eb0138b2dca455f702b9335eb03f40 (patch) | |
tree | 323af783bc8cc4c132d6e6b8e24c207dae67b0b8 | |
parent | 65500896a05344bdfd5fcbfa9a6456f48cd4e4a4 (diff) |
Ensure repeated compilation does not fail
Failure could result from the allocation of an address previously used
for the same class. The test is repeated for a surprisingly large
count of repetitions to increase the chance of this occurring.
Change-Id: I045902c50021f23adbbd61fccf41b9c38657387a
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 7 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/data/failedCompilation.1.qml | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/data/repeatedCompilation.qml | 9 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 43 |
5 files changed, 68 insertions, 4 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 2ebd13bb14..5111a4c087 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1962,7 +1962,14 @@ void QQmlEnginePrivate::trimCache() void QQmlEnginePrivate::typeUnloaded(QQmlTypeData *typeData) { - unregisterCompositeType(typeData->compiledData()->root); + if (typeData && typeData->compiledData()) { + const QMetaObject *mo = typeData->compiledData()->root; + if (QQmlPropertyCache *pc = propertyCache.value(mo)) { + propertyCache.remove(mo); + pc->release(); + } + unregisterCompositeType(mo); + } } bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d550a19874..228f2f96b6 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1244,6 +1244,7 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) if (!typeData) { typeData = new QQmlTypeData(url, None, this); + // TODO: if (compiledData == 0), is it safe to omit this insertion? m_typeCache.insert(url, typeData); QQmlDataLoader::load(typeData, mode); } @@ -1606,11 +1607,11 @@ void QQmlTypeLoader::trimCache(void (*callback)(void *, QQmlTypeData *), void *a TypeCache::Iterator iter = unneededTypes.last(); unneededTypes.removeLast(); + QQmlTypeData *typeData = iter.value(); if (callback) - (*callback)(arg, iter.value()); - + (*callback)(arg, typeData); m_typeCache.erase(iter); - iter.value()->release(); + typeData->release(); } } diff --git a/tests/auto/qml/qqmlengine/data/failedCompilation.1.qml b/tests/auto/qml/qqmlengine/data/failedCompilation.1.qml new file mode 100644 index 0000000000..0bd3cd0254 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/failedCompilation.1.qml @@ -0,0 +1,4 @@ +// No imports - intentional + +Item { +} diff --git a/tests/auto/qml/qqmlengine/data/repeatedCompilation.qml b/tests/auto/qml/qqmlengine/data/repeatedCompilation.qml new file mode 100644 index 0000000000..797381e54c --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/repeatedCompilation.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +VMEExtendVMEComponent { + property bool success: false + + Component.onCompleted: { + success = (foo == 'bar') && (bar == 'baz') + } +} diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 727635ee2c..85c32d8118 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -69,6 +69,9 @@ private slots: void clearComponentCache(); void trimComponentCache(); void trimComponentCache_data(); + void repeatedCompilation(); + void failedCompilation(); + void failedCompilation_data(); void outputWarningsToStandardError(); void objectOwnership(); void multipleEngines(); @@ -372,6 +375,46 @@ void tst_qqmlengine::trimComponentCache_data() QTest::newRow("ScriptComponent") << "testScriptComponent.qml"; } +void tst_qqmlengine::repeatedCompilation() +{ + QQmlEngine engine; + + for (int i = 0; i < 100; ++i) { + engine.collectGarbage(); + engine.trimComponentCache(); + + QQmlComponent component(&engine, testFileUrl("repeatedCompilation.qml")); + QVERIFY(component.isReady()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->property("success").toBool(), true); + } +} + +void tst_qqmlengine::failedCompilation() +{ + QFETCH(QString, file); + + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl(file)); + QVERIFY(!component.isReady()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object == 0); + + engine.collectGarbage(); + engine.trimComponentCache(); + engine.clearComponentCache(); +} + +void tst_qqmlengine::failedCompilation_data() +{ + QTest::addColumn<QString>("file"); + + QTest::newRow("Invalid URL") << "failedCompilation.does.not.exist.qml"; + QTest::newRow("Invalid content") << "failedCompilation.1.qml"; +} + static QStringList warnings; static void msgHandler(QtMsgType, const char *warning) { |