diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-01-15 16:43:31 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-01-23 12:03:40 +0100 |
commit | eb54a004799e39c8e06449c4851a988f273cd0db (patch) | |
tree | 50a5f119b1bb7daef9dfdb159024b056b9c58e75 | |
parent | 19ba561ff1329a9df7fb52e3815b5daa7e8613a4 (diff) |
QtQml: Move header verification into CompiledData::Unit
There is nothing that makes it depend on ExecutableCompilationUnit.
Change-Id: I482dfc0177530f748bb90e5373c64ca5558d8629
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/qml/common/qv4compileddata.cpp | 66 | ||||
-rw-r--r-- | src/qml/common/qv4compileddata_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4compilationunitmapper.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4compilationunitmapper_unix.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4compilationunitmapper_win.cpp | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit.cpp | 66 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 2 |
8 files changed, 84 insertions, 83 deletions
diff --git a/src/qml/common/qv4compileddata.cpp b/src/qml/common/qv4compileddata.cpp index 621a3c0326..9dee91f713 100644 --- a/src/qml/common/qv4compileddata.cpp +++ b/src/qml/common/qv4compileddata.cpp @@ -4,6 +4,7 @@ #include "qv4compileddata_p.h" #include <private/inlinecomponentutils_p.h> +#include <private/qml_compile_hash_p.h> #include <private/qqmlscriptdata_p.h> #include <private/qqmltypenamecache_p.h> #include <private/qv4resolvedtypereference_p.h> @@ -14,11 +15,76 @@ #include <QtCore/qscopeguard.h> #include <QtCore/qstandardpaths.h> +static_assert(QV4::CompiledData::QmlCompileHashSpace > QML_COMPILE_HASH_LENGTH); + +#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 +# ifdef Q_OS_LINUX +// Place on a separate section on Linux so it's easier to check from outside +// what the hash version is. +__attribute__((section(".qml_compile_hash"))) +# endif +const char qml_compile_hash[QV4::CompiledData::QmlCompileHashSpace] = QML_COMPILE_HASH; +static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) > QML_COMPILE_HASH_LENGTH, + "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); +#else +# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" +#endif + QT_BEGIN_NAMESPACE namespace QV4 { namespace CompiledData { + +bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const +{ + if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) { + *errorString = QStringLiteral("Magic bytes in the header do not match"); + return false; + } + + if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) { + *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2") + .arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); + return false; + } + + if (qtVersion != quint32(QT_VERSION)) { + *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2") + .arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16); + return false; + } + + if (sourceTimeStamp) { + // Files from the resource system do not have any time stamps, so fall back to the application + // executable. + if (!expectedSourceTimeStamp.isValid()) + expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); + + if (expectedSourceTimeStamp.isValid() + && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) { + *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); + return false; + } + } + +#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 + if (qstrncmp(qml_compile_hash, libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) { + *errorString = QStringLiteral("QML compile hashes don't match. Found %1 expected %2") + .arg(QString::fromLatin1( + QByteArray(libraryVersionHash, QML_COMPILE_HASH_LENGTH) + .toPercentEncoding()), + QString::fromLatin1( + QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH) + .toPercentEncoding())); + return false; + } +#else +#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" +#endif + return true; +} + /*! \internal This function creates a temporary key vector and sorts it to guarantuee a stable diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index 8fe6c8c87b..55e73bba7d 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -1371,6 +1371,8 @@ struct Unit const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); } const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); } + + bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const; }; static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp index f1c3476d40..e9915c7d26 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp @@ -4,7 +4,6 @@ #include "qv4compilationunitmapper_p.h" #include <private/qv4compileddata_p.h> -#include <private/qv4executablecompilationunit_p.h> #include <QtCore/qdatetime.h> #include <QtCore/qmutex.h> @@ -55,7 +54,7 @@ CompiledData::Unit *CompilationUnitMapper::get( CompilationUnitMapper mapper = cache.get(cacheFilePath); if (mapper.dataPtr) { auto *unit = reinterpret_cast<CompiledData::Unit *>(mapper.dataPtr); - if (ExecutableCompilationUnit::verifyHeader(unit, sourceTimeStamp, errorString)) { + if (unit->verifyHeader(sourceTimeStamp, errorString)) { *this = mapper; return unit; } diff --git a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp index 7b8178fe84..204e222121 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp @@ -3,13 +3,14 @@ #include "qv4compilationunitmapper_p.h" -#include <sys/mman.h> -#include <functional> #include <private/qcore_unix_p.h> -#include <QScopeGuard> -#include <QDateTime> +#include <private/qv4compileddata_p.h> + +#include <QtCore/qscopeguard.h> +#include <QtCore/qdatetime.h> -#include "qv4executablecompilationunit_p.h" +#include <functional> +#include <sys/mman.h> QT_BEGIN_NAMESPACE @@ -37,7 +38,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString)) + if (!header.verifyHeader(sourceTimeStamp, errorString)) return nullptr; // Data structure and qt version matched, so now we can access the rest of the file safely. diff --git a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp index 9ac4085453..73096207b4 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp @@ -3,10 +3,12 @@ #include "qv4compilationunitmapper_p.h" -#include "qv4executablecompilationunit_p.h" -#include <QScopeGuard> -#include <QFileInfo> -#include <QDateTime> +#include <private/qv4compileddata_p.h> + +#include <QtCore/qdatetime.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qscopeguard.h> + #include <qt_windows.h> QT_BEGIN_NAMESPACE @@ -45,7 +47,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString)) + if (!header.verifyHeader(sourceTimeStamp, errorString)) return nullptr; // Data structure and qt version matched, so now we can access the rest of the file safely. diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 812a3a5607..dfcdb8079c 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -17,7 +17,6 @@ #include <private/qqmlscriptdata_p.h> #include <private/qv4module_p.h> #include <private/qv4compilationunitmapper_p.h> -#include <private/qml_compile_hash_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qv4resolvedtypereference_p.h> #include <private/qv4objectiterator_p.h> @@ -27,21 +26,6 @@ #include <QtCore/qfileinfo.h> #include <QtCore/qcryptographichash.h> -static_assert(QV4::CompiledData::QmlCompileHashSpace > QML_COMPILE_HASH_LENGTH); - -#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 -# ifdef Q_OS_LINUX -// Place on a separate section on Linux so it's easier to check from outside -// what the hash version is. -__attribute__((section(".qml_compile_hash"))) -# endif -const char qml_compile_hash[QV4::CompiledData::QmlCompileHashSpace] = QML_COMPILE_HASH; -static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) > QML_COMPILE_HASH_LENGTH, - "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); -#else -# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" -#endif - QT_BEGIN_NAMESPACE namespace QV4 { @@ -714,56 +698,6 @@ QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) con #endif } -bool ExecutableCompilationUnit::verifyHeader( - const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, QString *errorString) -{ - if (strncmp(unit->magic, CompiledData::magic_str, sizeof(unit->magic))) { - *errorString = QStringLiteral("Magic bytes in the header do not match"); - return false; - } - - if (unit->version != quint32(QV4_DATA_STRUCTURE_VERSION)) { - *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2") - .arg(unit->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); - return false; - } - - if (unit->qtVersion != quint32(QT_VERSION)) { - *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2") - .arg(unit->qtVersion, 0, 16).arg(QT_VERSION, 0, 16); - return false; - } - - if (unit->sourceTimeStamp) { - // Files from the resource system do not have any time stamps, so fall back to the application - // executable. - if (!expectedSourceTimeStamp.isValid()) - expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); - - if (expectedSourceTimeStamp.isValid() - && expectedSourceTimeStamp.toMSecsSinceEpoch() != unit->sourceTimeStamp) { - *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); - return false; - } - } - -#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 - if (qstrncmp(qml_compile_hash, unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) { - *errorString = QStringLiteral("QML compile hashes don't match. Found %1 expected %2") - .arg(QString::fromLatin1( - QByteArray(unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH) - .toPercentEncoding()), - QString::fromLatin1( - QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH) - .toPercentEncoding())); - return false; - } -#else -#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" -#endif - return true; -} - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 58d252c36c..48ebee6fca 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -186,9 +186,6 @@ public: QString translateFrom(TranslationDataIndex index) const; - static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, - QString *errorString); - Heap::Module *module() const { return m_module; } void setModule(Heap::Module *module) { m_module = module; } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 0b6ea5c977..66f77edb39 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1709,7 +1709,7 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit( for (const auto lookup : std::as_const(data->lookupCachedQmlUnit)) { if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) { QString error; - if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) { + if (!unit->qmlData->verifyHeader(QDateTime(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error; if (status) *status = CachedUnitLookupError::VersionMismatch; |