From 4c1a51006e5936dc69e3373539787120092f6719 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 21 Jul 2016 16:30:57 +0200 Subject: Improve robustness of qml disk caching Perform various basic checks before proceeding to load an existing cache file, including the qt version, architecture, data structure version and others. Change-Id: Ie822b056e944ac120643aad260e97f62616688bf Reviewed-by: Erik Verbruggen --- tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 121 +++++++++++++++++++++-- 1 file changed, 114 insertions(+), 7 deletions(-) (limited to 'tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp') diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index bb78f2856f..1fe63bb99a 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -29,6 +29,11 @@ #include #include +#include +#include +#include +#include +#include #include #include #include @@ -42,6 +47,7 @@ private slots: void regenerateAfterChange(); void registerImportForImplicitComponent(); + void basicVersionChecks(); }; struct TestCompiler @@ -58,11 +64,8 @@ struct TestCompiler bool compile(const QByteArray &contents) { - if (currentMapping) { - mappedFile.unmap(currentMapping); - currentMapping = nullptr; - } - mappedFile.close(); + closeMapping(); + engine->clearComponentCache(); // Qt API limits the precision of QFileInfo::modificationTime() to seconds, so to ensure that // the newly written file has a modification date newer than an existing cache file, we must @@ -106,6 +109,44 @@ struct TestCompiler return unitPtr; } + typedef void (*HeaderTweakFunction)(QV4::CompiledData::Unit *header); + bool tweakHeader(HeaderTweakFunction function) + { + closeMapping(); + + QFile f(cacheFilePath); + if (!f.open(QIODevice::ReadWrite)) + return false; + QV4::CompiledData::Unit header; + if (f.read(reinterpret_cast(&header), sizeof(header)) != sizeof(header)) + return false; + function(&header); + f.seek(0); + return f.write(reinterpret_cast(&header), sizeof(header)) == sizeof(header); + } + + bool verify() + { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString); + } + + void closeMapping() + { + if (currentMapping) { + mappedFile.unmap(currentMapping); + currentMapping = nullptr; + } + mappedFile.close(); + } + + void clearCache() + { + closeMapping(); + QFile::remove(cacheFilePath); + } + QQmlEngine *engine; const QTemporaryDir tempDir; const QString testFilePath; @@ -151,8 +192,6 @@ void tst_qmldiskcache::regenerateAfterChange() QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); } - engine.clearComponentCache(); - { const QByteArray newContents = QByteArrayLiteral("import QtQml 2.0\n" "QtObject {\n" @@ -214,6 +253,74 @@ void tst_qmldiskcache::registerImportForImplicitComponent() } } +void tst_qmldiskcache::basicVersionChecks() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + "}"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->qtVersion = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Qt version mismatch. Found 0 expected %1").arg(QT_VERSION, 0, 16)); + testCompiler.clearCache(); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->version = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->architectureIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi())); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->codeGeneratorIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName)); + } +} + QTEST_MAIN(tst_qmldiskcache) #include "tst_qmldiskcache.moc" -- cgit v1.2.3