aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmltypeloader.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2016-07-28 17:40:36 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2016-08-04 14:32:08 +0000
commitd77e544a568dbfff698c4d37c669bc991383fe9b (patch)
treefc48e7dae9ba9e53a6de1018ff3436182e7a8f58 /src/qml/qml/qqmltypeloader.cpp
parent1534dd6d97c49f5c7e0392df9c95198311b5b817 (diff)
Safeguard disk cache loading with checksum verification
When loading a QML component from the disk cache, compare the checksum of the dependent types against the checksum when the cache was created. Any change in the meta-object of a dependent type should trigger a re-creation discard of the cache and consequent re-creation (in the test-case). Unfortunately this also requires extending the existing hack in the unit test to deal with the low second precision on HFS+ in order to pass the tests. Change-Id: Ib8e899347680f7be676788388e9c23a09b0277e3 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/qml/qqmltypeloader.cpp')
-rw-r--r--src/qml/qml/qqmltypeloader.cpp98
1 files changed, 60 insertions, 38 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5bc9c8ac25..538e630e98 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2136,21 +2136,16 @@ bool QQmlTypeData::tryLoadFromDiskCache()
return true;
}
-void QQmlTypeData::rebuildTypeAndPropertyCaches()
+void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
+ m_compiledData->importCache = importCache;
+ m_compiledData->resolvedTypes = resolvedTypeCache;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
{
- QQmlCompileError error = buildTypeResolutionCaches(&m_compiledData->importCache, &m_compiledData->resolvedTypes);
- if (error.isSet()) {
- setError(error);
- return;
- }
- }
-
- {
QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, engine, m_compiledData, &m_importCache);
QQmlCompileError error = propertyCacheCreator.buildMetaObjects();
if (error.isSet()) {
@@ -2231,21 +2226,41 @@ void QQmlTypeData::done()
}
}
+ QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
+ {
+ QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlEngine *const engine = typeLoader()->engine();
+
+ // verify if any dependencies changed if we're using a cache
+ if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) {
+ if (!loadFromSource())
+ return;
+ m_backupSourceCode.clear();
+ m_compiledData = nullptr;
+ }
+
if (!m_document.isNull()) {
// Compile component
- compile();
+ compile(importCache, resolvedTypeCache);
} else {
- rebuildTypeAndPropertyCaches();
+ createTypeAndPropertyCaches(importCache, resolvedTypeCache);
}
if (isError())
return;
{
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
{
// Sanity check property bindings
- QQmlPropertyValidator validator(engine, m_importCache, m_compiledData);
+ QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
QVector<QQmlCompileError> errors = validator.validate();
if (!errors.isEmpty()) {
setError(errors);
@@ -2253,7 +2268,7 @@ void QQmlTypeData::done()
}
}
- m_compiledData->finalize(engine);
+ m_compiledData->finalize(enginePrivate);
}
{
@@ -2336,19 +2351,43 @@ bool QQmlTypeData::loadImplicitImport()
void QQmlTypeData::dataReceived(const Data &data)
{
+ QString error;
+ m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp);
+ // if we failed to read the source code, process it _after_ we've tried
+ // to use the disk cache, in order to support scenarios where the source
+ // was removed deliberately.
+
if (tryLoadFromDiskCache())
return;
- qint64 sourceTimeStamp;
- QString error;
- QString code = QString::fromUtf8(data.readAll(&error, &sourceTimeStamp));
+ if (isError())
+ return;
+
if (!error.isEmpty()) {
setError(error);
return;
}
+
+ if (!loadFromSource())
+ return;
+
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+{
QQmlEngine *qmlEngine = typeLoader()->engine();
m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0));
- m_document->jsModule.sourceTimeStamp = sourceTimeStamp;
+ unit->loadIR(m_document.data(), unit);
+ continueLoadFromIR();
+}
+
+bool QQmlTypeData::loadFromSource()
+{
+ QString code = QString::fromUtf8(m_backupSourceCode);
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0));
+ m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp;
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
@@ -2362,18 +2401,9 @@ void QQmlTypeData::dataReceived(const Data &data)
errors << e;
}
setError(errors);
- return;
+ return false;
}
-
- continueLoadFromIR();
-}
-
-void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
-{
- QQmlEngine *qmlEngine = typeLoader()->engine();
- m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0));
- unit->loadIR(m_document.data(), unit);
- continueLoadFromIR();
+ return true;
}
void QQmlTypeData::continueLoadFromIR()
@@ -2468,18 +2498,10 @@ QString QQmlTypeData::stringAt(int index) const
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile()
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData.isNull());
- QQmlRefPointer<QQmlTypeNameCache> importCache;
- QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
- QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
- if (error.isSet()) {
- setError(error);
- return;
- }
-
QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), this, m_document.data(), importCache, resolvedTypeCache);
m_compiledData = compiler.compile();
if (!m_compiledData) {