From 4767dfcce32ca69d88861f5ab8a18b0a1110b0b4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 8 Jul 2021 13:01:36 +0200 Subject: [PATCH 1/3] qmake: Fix issues with executing system calls Do not try to reuse the QFutureInterface that is used for the parsing process. Reusing the QFutureInterface can lead to issues. So far no problems were triggered, but a30aa4421a0257b048197b51330e6bf5c2732af5 introduced a watcher that tells the qmake parser to ignore all system calls after the future was canceled. This was somehow, sometimes triggered on the reused QFutureInterface even though the user didn't cancel anyhing, leading to all system calls to bail out in the subsequent run. Using a new QFutureInterface instance for each parsing run solves the issue. Amends a30aa4421a0257b048197b51330e6bf5c2732af5 Fixes: QTCREATORBUG-25970 Change-Id: I6836c97038c36968e93815c6121bc284edbe19bb Reviewed-by: Christian Kandeler --- .../qmakeprojectmanager/qmakeproject.cpp | 34 ++++++++++++------- .../qmakeprojectmanager/qmakeproject.h | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 387c0688a4b..f62398a315c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -284,8 +284,11 @@ QmakeBuildSystem::~QmakeBuildSystem() delete m_qmakeVfs; m_qmakeVfs = nullptr; - m_asyncUpdateFutureInterface.reportCanceled(); - m_asyncUpdateFutureInterface.reportFinished(); + if (m_asyncUpdateFutureInterface) { + m_asyncUpdateFutureInterface->reportCanceled(); + m_asyncUpdateFutureInterface->reportFinished(); + m_asyncUpdateFutureInterface.reset(); + } } void QmakeBuildSystem::updateCodeModels() @@ -592,8 +595,9 @@ void QmakeBuildSystem::incrementPendingEvaluateFutures() } ++m_pendingEvaluateFuturesCount; TRACE("pending inc to: " << m_pendingEvaluateFuturesCount); - m_asyncUpdateFutureInterface.setProgressRange(m_asyncUpdateFutureInterface.progressMinimum(), - m_asyncUpdateFutureInterface.progressMaximum() + 1); + m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(), + m_asyncUpdateFutureInterface->progressMaximum() + + 1); } void QmakeBuildSystem::decrementPendingEvaluateFutures() @@ -606,15 +610,17 @@ void QmakeBuildSystem::decrementPendingEvaluateFutures() return; // We are closing the project! } - m_asyncUpdateFutureInterface.setProgressValue(m_asyncUpdateFutureInterface.progressValue() + 1); + m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + + 1); if (m_pendingEvaluateFuturesCount == 0) { // We are done! setRootProjectNode(QmakeNodeTreeBuilder::buildTree(this)); if (!m_rootProFile->validParse()) - m_asyncUpdateFutureInterface.reportCanceled(); + m_asyncUpdateFutureInterface->reportCanceled(); - m_asyncUpdateFutureInterface.reportFinished(); + m_asyncUpdateFutureInterface->reportFinished(); + m_asyncUpdateFutureInterface.reset(); m_cancelEvaluate = false; // TODO clear the profile cache ? @@ -660,12 +666,13 @@ void QmakeBuildSystem::asyncUpdate() m_qmakeVfs->invalidateCache(); } - m_asyncUpdateFutureInterface.setProgressRange(0, 0); - Core::ProgressManager::addTask(m_asyncUpdateFutureInterface.future(), + m_asyncUpdateFutureInterface.reset(new QFutureInterface); + m_asyncUpdateFutureInterface->setProgressRange(0, 0); + Core::ProgressManager::addTask(m_asyncUpdateFutureInterface->future(), tr("Reading Project \"%1\"").arg(project()->displayName()), Constants::PROFILE_EVALUATE); - m_asyncUpdateFutureInterface.reportStarted(); + m_asyncUpdateFutureInterface->reportStarted(); const auto watcher = new QFutureWatcher(this); connect(watcher, &QFutureWatcher::canceled, this, [this, watcher] { if (!m_qmakeGlobals) @@ -677,7 +684,7 @@ void QmakeBuildSystem::asyncUpdate() watcher->disconnect(); watcher->deleteLater(); }); - watcher->setFuture(m_asyncUpdateFutureInterface.future()); + watcher->setFuture(m_asyncUpdateFutureInterface->future()); const Kit *const k = kit(); QtSupport::BaseQtVersion *const qtVersion = QtSupport::QtKitAspect::qtVersion(k); @@ -688,8 +695,9 @@ void QmakeBuildSystem::asyncUpdate() .arg(project()->displayName(), k->displayName()) : tr("Cannot parse project \"%1\": No kit selected.").arg(project()->displayName()); proFileParseError(errorMessage, project()->projectFilePath()); - m_asyncUpdateFutureInterface.reportCanceled(); - m_asyncUpdateFutureInterface.reportFinished(); + m_asyncUpdateFutureInterface->reportCanceled(); + m_asyncUpdateFutureInterface->reportFinished(); + m_asyncUpdateFutureInterface.reset(); return; } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index fba8c8db7a5..89397407abb 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -198,7 +198,7 @@ private: QString m_qmakeSysroot; - QFutureInterface m_asyncUpdateFutureInterface; + std::unique_ptr> m_asyncUpdateFutureInterface; int m_pendingEvaluateFuturesCount = 0; AsyncUpdateState m_asyncUpdateState = Base; bool m_cancelEvaluate = false; From 0568be071d5523478775019c9dd28d5a081efa74 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 9 Jul 2021 11:52:13 +0200 Subject: [PATCH 2/3] Add changes file for 4.15.2 Change-Id: I691d64c4faac7158009d6f93a089cab184934893 Reviewed-by: Leena Miettinen --- dist/changes-4.15.2.md | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dist/changes-4.15.2.md diff --git a/dist/changes-4.15.2.md b/dist/changes-4.15.2.md new file mode 100644 index 00000000000..cf053f0046a --- /dev/null +++ b/dist/changes-4.15.2.md @@ -0,0 +1,55 @@ +Qt Creator 4.15.2 +================= + +Qt Creator version 4.15.2 contains bug fixes. + +The most important changes are listed in this document. For a complete +list of changes, see the Git log for the Qt Creator sources that +you can check out from the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/v4.15.1..v4.15.2 + +Projects +-------- + +### CMake + +* Improved performance after project load and reparse +* Fixed crash on session switch (QTCREATORBUG-25837) + +### qmake + +* Fixed issues with executing system calls (QTCREATORBUG-25970) + +Test Integration +---------------- + +### CTest + +* Fixed test detection if `ctest` takes long to run (QTCREATORBUG-25851) + +Platforms +--------- + +### WASM + +* Fixed Python version that is on Windows (QTCREATORBUG-25897) + +Credits for these changes go to: +-------------------------------- +Ahmad Samir +Alessandro Portale +Christian Stenger +Cristian Adam +Eike Ziller +Ivan Komissarov +Kai Köhne +Knud Dollereder +Michael Winkelmann +Mitch Curtis +Robert Löhning +Thomas Hartmann +Tim Blechmann +Tim Jenssen +Tuomo Pelkonen From c3e413a8643857111ea80747605ba2cf5c2e328b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 9 Jul 2021 11:22:22 +0200 Subject: [PATCH 3/3] proparser: Update ProItems to state in Qt 6.2 Except for our Qt 5 workarounds with toStringView, qHash return value, and ProStringList which must be an explicit QVector for Qt 5. Most importantly that pulls in a change to ProString::toQString(QString &tmp) const from 76004502baa118016c8e0f32895af7a822f1ba37 in qtbase, which replaces a setRawData call which otherwise leads to severe issues when built with Qt 6. Fixes: QTCREATORBUG-25574 Change-Id: I488b4e0b63becc59a4ea34aace5c249921fa1a60 Reviewed-by: Joerg Bornemann Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/shared/proparser/proitems.cpp | 18 +++++- src/shared/proparser/proitems.h | 94 +++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index f689c419237..1f4a436115e 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -25,6 +25,7 @@ #include "proitems.h" +#include #include #include #include @@ -50,6 +51,11 @@ ProString::ProString() : { } +ProString::ProString(const ProString &other) : + m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash) +{ +} + ProString::ProString(const ProString &other, OmitPreHashing) : m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000) { @@ -72,13 +78,13 @@ ProString::ProString(Utils::StringView str) : } ProString::ProString(const char *str, DoPreHashing) : - m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0) + m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0) { updatedHash(); } ProString::ProString(const char *str) : - m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0), m_hash(0x80000000) + m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0), m_hash(0x80000000) { } @@ -148,7 +154,8 @@ QString ProString::toQString() const QString &ProString::toQString(QString &tmp) const { - return tmp.setRawData(m_string.constData() + m_offset, m_length); + tmp = m_string.mid(m_offset, m_length); + return tmp; } ProString &ProString::prepend(const ProString &other) @@ -493,4 +500,9 @@ ProKey ProFile::getHashStr(const ushort *&tPtr) return ret; } +QDebug operator<<(QDebug debug, const ProString &str) +{ + return debug << str.toQString(); +} + QT_END_NAMESPACE diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 3e0686fe136..9d851a9d578 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -64,6 +64,8 @@ class ProFile; class ProString { public: ProString(); + ProString(const ProString &other); + ProString &operator=(const ProString &) = default; template ProString &operator=(const QStringBuilder &str) { return *this = QString(str); } @@ -74,7 +76,6 @@ public: ProString(const QStringBuilder &str) : ProString(QString(str)) {} - ProString(const QString &str, int offset, int length); void setValue(const QString &str); void clear() { m_string.clear(); m_length = 0; } @@ -83,14 +84,14 @@ public: int sourceFile() const { return m_file; } ProString &prepend(const ProString &other); - ProString &append(const ProString &other, bool *pending = 0); + ProString &append(const ProString &other, bool *pending = nullptr); ProString &append(const QString &other) { return append(ProString(other)); } template ProString &append(const QStringBuilder &other) { return append(QString(other)); } ProString &append(const QLatin1String other); ProString &append(const char *other) { return append(QLatin1String(other)); } ProString &append(QChar other); - ProString &append(const ProStringList &other, bool *pending = 0, bool skipEmpty1st = false); + ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false); ProString &operator+=(const ProString &other) { return append(other); } ProString &operator+=(const QString &other) { return append(other); } template @@ -146,9 +147,9 @@ public: bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } - int toLongLong(bool *ok = 0, int base = 10) const { return toStringView().toLongLong(ok, base); } - int toInt(bool *ok = 0, int base = 10) const { return toStringView().toInt(ok, base); } - short toShort(bool *ok = 0, int base = 10) const { return toStringView().toShort(ok, base); } + qlonglong toLongLong(bool *ok = nullptr, int base = 10) const { return toStringView().toLongLong(ok, base); } + int toInt(bool *ok = nullptr, int base = 10) const { return toStringView().toInt(ok, base); } + short toShort(bool *ok = nullptr, int base = 10) const { return toStringView().toShort(ok, base); } uint hash() const { return m_hash; } static uint hash(const QChar *p, int n); @@ -185,7 +186,8 @@ private: friend QString operator+(const ProString &one, const ProString &two); friend class ProKey; }; -Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProString, Q_RELOCATABLE_TYPE); + class ProKey : public ProString { public: @@ -195,7 +197,6 @@ public: ProKey(const QStringBuilder &str) : ProString(str) {} - PROITEM_EXPLICIT ProKey(const char *str); ProKey(const QString &str, int off, int len); ProKey(const QString &str, int off, int len, uint hash); @@ -217,7 +218,7 @@ public: private: ProKey(const ProString &other); }; -Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProKey, Q_RELOCATABLE_TYPE); template <> struct QConcatenable : private QAbstractConcatenable { @@ -228,6 +229,8 @@ template <> struct QConcatenable : private QAbstractConcatenable static inline void appendTo(const ProString &a, QChar *&out) { const auto n = a.size(); + if (!n) + return; memcpy(out, a.toStringView().data(), sizeof(QChar) * n); out += n; } @@ -242,6 +245,8 @@ template <> struct QConcatenable : private QAbstractConcatenable static inline void appendTo(const ProKey &a, QChar *&out) { const auto n = a.size(); + if (!n) + return; memcpy(out, a.toStringView().data(), sizeof(QChar) * n); out += n; } @@ -257,6 +262,54 @@ QTextStream &operator<<(QTextStream &t, const ProString &str); template QTextStream &operator<<(QTextStream &t, const QStringBuilder &str) { return t << QString(str); } +// This class manages read-only access to a ProString via a raw data QString +// temporary, ensuring that the latter is accessed exclusively. +class ProStringRoUser +{ +public: + ProStringRoUser(QString &rs) + { + m_rs = &rs; + } + ProStringRoUser(const ProString &ps, QString &rs) + : ProStringRoUser(rs) + { + ps.toQString(rs); + } + // No destructor, as a RAII pattern cannot be used: references to the + // temporary string can legitimately outlive instances of this class + // (if they are held by Qt, e.g. in QRegExp). + QString &set(const ProString &ps) { return ps.toQString(*m_rs); } + QString &str() { return *m_rs; } + +protected: + QString *m_rs; +}; + +// This class manages read-write access to a ProString via a raw data QString +// temporary, ensuring that the latter is accessed exclusively, and that raw +// data does not leak outside its source's refcounting. +class ProStringRwUser : public ProStringRoUser +{ +public: + ProStringRwUser(QString &rs) + : ProStringRoUser(rs), m_ps(nullptr) {} + ProStringRwUser(const ProString &ps, QString &rs) + : ProStringRoUser(ps, rs), m_ps(&ps) {} + QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); } + ProString extract(const QString &s) const + { return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); } + ProString extract(const QString &s, const ProStringRwUser &other) const + { + if (other.m_ps && s.isSharedWith(*other.m_rs)) + return *other.m_ps; + return extract(s); + } + +private: + const ProString *m_ps; +}; + class ProStringList : public QVector { public: ProStringList() {} @@ -290,21 +343,12 @@ public: { return contains(ProString(str), cs); } bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; }; -Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProStringList, Q_RELOCATABLE_TYPE); inline ProStringList operator+(const ProStringList &one, const ProStringList &two) { ProStringList ret = one; ret += two; return ret; } -typedef QHash ProValueMap; - -// For std::list (sic!) -#ifdef Q_CC_MSVC -inline bool operator<(const ProValueMap &, const ProValueMap &) -{ - Q_ASSERT(false); - return false; -} -#endif +typedef QMap ProValueMap; // These token definitions affect both ProFileEvaluator and ProWriter enum ProToken { @@ -419,7 +463,7 @@ class ProFunctionDef { public: ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); } ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } - ProFunctionDef(ProFunctionDef &&other) Q_DECL_NOTHROW + ProFunctionDef(ProFunctionDef &&other) noexcept : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } ~ProFunctionDef() { if (m_pro) m_pro->deref(); } ProFunctionDef &operator=(const ProFunctionDef &o) @@ -433,13 +477,13 @@ public: } return *this; } - ProFunctionDef &operator=(ProFunctionDef &&other) Q_DECL_NOTHROW + ProFunctionDef &operator=(ProFunctionDef &&other) noexcept { ProFunctionDef moved(std::move(other)); swap(moved); return *this; } - void swap(ProFunctionDef &other) Q_DECL_NOTHROW + void swap(ProFunctionDef &other) noexcept { qSwap(m_pro, other.m_pro); qSwap(m_offset, other.m_offset); @@ -452,11 +496,13 @@ private: int m_offset; }; -Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProFunctionDef, Q_RELOCATABLE_TYPE); struct ProFunctionDefs { QHash testFunctions; QHash replaceFunctions; }; +QDebug operator<<(QDebug debug, const ProString &str); + QT_END_NAMESPACE