Fix crash with recursively loading cached compilation units
authorSimon Hausmann <simon.hausmann@digia.com>
Tue, 24 Jun 2014 08:35:42 +0000 (10:35 +0200)
committerSimon Hausmann <simon.hausmann@digia.com>
Fri, 22 Aug 2014 19:13:44 +0000 (21:13 +0200)
When a cached compilation unit depends on an import that is implemented as a
Qml C++ plugin and that plugin in turn loads an asynchronous component that is
cached, we would get a crash in the typeloader and a failing assertion
(ASSERT: "d->m_mainThreadWaiting == false" in file qml/ftw/qqmlthread.cpp, line 300)

This is because we did not implement the asynchronous loading within the loader
thread for cached compilation units. This is simply done using a posted event,
using the same mechanism used for other async load methods.

Change-Id: Iefce67ab634ce26122c348dcdfc8e66b00fec671
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/qml/qqmltypeloader.cpp
src/qml/qml/qqmltypeloader_p.h

index 7fc08bd..4412f95 100644 (file)
@@ -148,6 +148,7 @@ public:
     void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
     void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
     void loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
+    void loadWithCachedUnitAsync(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
     void callCompleted(QQmlDataBlob *b);
     void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
     void initializeEngine(QQmlExtensionInterface *, const char *);
@@ -785,6 +786,12 @@ void QQmlDataLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate
     callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
 }
 
+void QQmlDataLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+{
+    b->addref();
+    postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
 void QQmlDataLoaderThread::callCompleted(QQmlDataBlob *b)
 {
     b->addref();
@@ -979,7 +986,7 @@ void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da
     }
 }
 
-void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
 {
 #ifdef DATABLOB_DEBUG
     qWarning("QQmlDataLoader::loadWithUnitFcatory(%s, data): %s thread", qPrintable(blob->m_url.toString()),
@@ -992,12 +999,18 @@ void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::C
         unlock();
         loadWithCachedUnitThread(blob, unit);
         lock();
-    } else {
+    } else if (mode == PreferSynchronous) {
         unlock();
         m_thread->loadWithCachedUnit(blob, unit);
         lock();
         if (!blob->isCompleteOrError())
             blob->m_data.setIsAsync(true);
+    } else {
+        Q_ASSERT(mode == Asynchronous);
+        blob->m_data.setIsAsync(true);
+        unlock();
+        m_thread->loadWithCachedUnitAsync(blob, unit);
+        lock();
     }
 }
 
@@ -1601,7 +1614,7 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
         // TODO: if (compiledData == 0), is it safe to omit this insertion?
         m_typeCache.insert(url, typeData);
         if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
-            QQmlDataLoader::loadWithCachedUnit(typeData, cachedUnit);
+            QQmlDataLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
         } else {
             QQmlDataLoader::load(typeData, mode);
         }
index b09ac15..dff6b36 100644 (file)
@@ -229,7 +229,7 @@ public:
 
     void load(QQmlDataBlob *, Mode = PreferSynchronous);
     void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
-    void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
+    void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode = PreferSynchronous);
 
     QQmlEngine *engine() const;
     void initializeEngine(QQmlExtensionInterface *, const char *);