From 7935d86e7dc4ad994455aba604c8a51b01470cd5 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Thu, 28 Mar 2019 13:43:50 +0100 Subject: [PATCH 01/12] Populate test data for reverse lookups using system tools Hardcoding IP addresses and their respective DNS records is fragile. We care about Qt producing the same result as other DNS querying tools, so testing that instead. Running a python script for this is easiest, and assumed to be quite reliable. In case where python fails/is not present, fall back to nslookup. That tool is available on Linux, macOS, and Windows, although the output it produces varies. This change implements very basic line-parsing that can interpret the various results encountered during testing on those platforms. This also reverts commit bbaceff253fae13d8e56691bc9de7e1981db5118, which blacklisted the tests that failed due to changes in DNS records. Use the opportunity to replace usage of gitorious.org. Change-Id: I967de226bd603c805df7fe3ed4e871d92d2d0750 Reviewed-by: Timur Pocheptsov --- tests/auto/network/kernel/qhostinfo/BLACKLIST | 2 - .../kernel/qhostinfo/tst_qhostinfo.cpp | 68 ++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/tests/auto/network/kernel/qhostinfo/BLACKLIST b/tests/auto/network/kernel/qhostinfo/BLACKLIST index cd4d4eb03c0..87c5fe991fa 100644 --- a/tests/auto/network/kernel/qhostinfo/BLACKLIST +++ b/tests/auto/network/kernel/qhostinfo/BLACKLIST @@ -4,5 +4,3 @@ windows ci [blockingLookup:a-plus-aaaa] windows ci -[reverseLookup:google-public-dns-a.google.com] -ci diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 82825f608ca..0a130d363e4 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -396,6 +396,68 @@ void tst_QHostInfo::lookupConnectToLambda() QCOMPARE(tmp.join(' '), expected.join(' ')); } +static QStringList reverseLookupHelper(const QString &ip) +{ + QStringList results; + + const QString pythonCode = + "import socket;" + "import sys;" + "print (socket.getnameinfo((sys.argv[1], 0), 0)[0]);"; + + QList lines; + QProcess python; + python.setProcessChannelMode(QProcess::ForwardedErrorChannel); + python.start("python", QStringList() << QString("-c") << pythonCode << ip); + if (python.waitForFinished()) { + if (python.exitStatus() == QProcess::NormalExit && python.exitCode() == 0) + lines = python.readAllStandardOutput().split('\n'); + for (QByteArray line : lines) { + if (!line.isEmpty()) + results << line.trimmed(); + } + if (!results.isEmpty()) + return results; + } + + qDebug() << "Python failed, falling back to nslookup"; + QProcess lookup; + lookup.setProcessChannelMode(QProcess::ForwardedErrorChannel); + lookup.start("nslookup", QStringList(ip)); + if (!lookup.waitForFinished()) { + results << "nslookup failure"; + qDebug() << "nslookup failure"; + return results; + } + lines = lookup.readAllStandardOutput().split('\n'); + + QByteArray name; + + const QByteArray nameMarkerNix("name ="); + const QByteArray nameMarkerWin("Name:"); + const QByteArray addressMarkerWin("Address:"); + + for (QByteArray line : lines) { + int index = -1; + if ((index = line.indexOf(nameMarkerNix)) != -1) { // Linux and macOS + name = line.mid(index + nameMarkerNix.length()).chopped(1).trimmed(); + results << name; + } else if (line.startsWith(nameMarkerWin)) { // Windows formatting + name = line.mid(line.lastIndexOf(" ")).trimmed(); + } else if (line.startsWith(addressMarkerWin)) { + QByteArray address = line.mid(addressMarkerWin.length()).trimmed(); + if (address == ip) { + results << name; + } + } + } + + if (results.isEmpty()) { + qDebug() << "Failure to parse nslookup output: " << lines; + } + return results; +} + void tst_QHostInfo::reverseLookup_data() { QTest::addColumn("address"); @@ -403,8 +465,8 @@ void tst_QHostInfo::reverseLookup_data() QTest::addColumn("err"); QTest::addColumn("ipv6"); - QTest::newRow("google-public-dns-a.google.com") << QString("8.8.8.8") << QStringList(QString("google-public-dns-a.google.com")) << 0 << false; - QTest::newRow("gitorious.org") << QString("87.238.52.168") << QStringList(QString("gitorious.org")) << 0 << false; + QTest::newRow("dns.google") << QString("8.8.8.8") << reverseLookupHelper("8.8.8.8") << 0 << false; + QTest::newRow("one.one.one.one") << QString("1.1.1.1") << reverseLookupHelper("1.1.1.1") << 0 << false; QTest::newRow("bogus-name") << QString("1::2::3::4") << QStringList() << 1 << true; } @@ -422,6 +484,8 @@ void tst_QHostInfo::reverseLookup() QHostInfo info = QHostInfo::fromName(address); if (err == 0) { + if (!hostNames.contains(info.hostName())) + qDebug() << "Failure: expecting" << hostNames << ",got " << info.hostName(); QVERIFY(hostNames.contains(info.hostName())); QCOMPARE(info.addresses().first(), QHostAddress(address)); } else { From 5a168507b1a3413d71cddfc5245adedcfe46b55d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 4 Apr 2019 09:07:22 +0200 Subject: [PATCH 02/12] Manual dialog test: Output URLs when testing QFileDialog Change-Id: Icfaedcd68ff387cc888e41ec0b1db1810122b229 Reviewed-by: Joerg Bornemann --- tests/manual/dialogs/filedialogpanel.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/manual/dialogs/filedialogpanel.cpp b/tests/manual/dialogs/filedialogpanel.cpp index 9e3c761cfff..62d03e735dd 100644 --- a/tests/manual/dialogs/filedialogpanel.cpp +++ b/tests/manual/dialogs/filedialogpanel.cpp @@ -505,8 +505,15 @@ void FileDialogPanel::accepted() Q_ASSERT(d); m_result.clear(); QDebug(&m_result).nospace() +#if QT_VERSION >= 0x050000 + << "URLs: " << d->selectedUrls() << '\n' +#endif << "Files: " << d->selectedFiles() - << "\nDirectory: " << d->directory().absolutePath() + << "\nDirectory: " +#if QT_VERSION >= 0x050000 + << d->directoryUrl() << ", " +#endif + << d->directory().absolutePath() << "\nName filter: " << d->selectedNameFilter(); QTimer::singleShot(0, this, SLOT(showAcceptedResult())); // Avoid problems with the closing (modal) dialog as parent. } From b404cd930e32520f8ad62088c9ed31f33ce95933 Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Thu, 4 Apr 2019 17:17:59 +0300 Subject: [PATCH 03/12] Make qt_is_ascii work properly on big endian systems Change-Id: Ia053fbc854a77e333edadb0be6c2e04826b8fbdb Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index d8bfb69a8bd..4852d20082e 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -501,7 +501,11 @@ bool qt_is_ascii(const char *&ptr, const char *end) Q_DECL_NOTHROW while (ptr + 4 <= end) { quint32 data = qFromUnaligned(ptr); if (data &= 0x80808080U) { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + uint idx = qCountLeadingZeroBits(data); +#else uint idx = qCountTrailingZeroBits(data); +#endif ptr += idx / 8; return false; } From 4e24bb24a234ee85fca25f9a117de7380083f593 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 5 Apr 2019 09:02:28 +0200 Subject: [PATCH 04/12] Remove noisy warning for undefined QGradient preset This runtime warning was recently introduced in the fix for an assert/crash when creating a brush with an invalid Preset value. However, that overlooked the usage where an unknown value is passed to QGradient constructor, and the code afterwards checks if the result is a NoGradient or not. It turns out that such usage is already established as legitimate, including in the Qt Quick Rectangle code, so this warning would be spit out continuously for perfectly legal qml code. Change-Id: Id60aed0817da0214b6cf17edd245f67e26470413 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qbrush.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index bcc23fa6833..d071f665bb3 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -1378,10 +1378,8 @@ QGradient::QGradient(Preset preset) }(); const QJsonValue presetData = jsonPresets[preset - 1]; - if (!presetData.isObject()) { - qWarning("QGradient: Undefined preset %i", preset); + if (!presetData.isObject()) return; - } m_type = LinearGradient; setCoordinateMode(ObjectMode); From 5f7b0e5ff4410a596168ee667b71afaa7b18eee8 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 4 Apr 2019 16:47:29 +0200 Subject: [PATCH 05/12] qmake: Remove dead code Silences a clang warning Change-Id: I5ade49326afcce964ffb5c24b5708977950d123e Reviewed-by: Joerg Bornemann --- qmake/generators/mac/pbuilder_pbx.cpp | 2 +- qmake/generators/makefile.cpp | 2 +- qmake/generators/unix/unixmake2.cpp | 2 +- qmake/meta.cpp | 7 ------- qmake/meta.h | 2 -- 5 files changed, 3 insertions(+), 12 deletions(-) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 5407ed6c69c..07832041a76 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -856,7 +856,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) QString lib_file = QMakeMetaInfo::checkLib(Option::normalizePath( (*lit) + Option::dir_sep + lib + Option::prl_ext)); if (!lib_file.isEmpty()) { - QMakeMetaInfo libinfo(project); + QMakeMetaInfo libinfo; if(libinfo.readLib(lib_file)) { if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) { library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET"); diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index ab261d02f19..e9dccf0c463 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -912,7 +912,7 @@ MakefileGenerator::processPrlFileCore(QString &origFile, const QStringRef &origN const QString meta_file = QMakeMetaInfo::checkLib(fixedFile); if (meta_file.isEmpty()) return false; - QMakeMetaInfo libinfo(project); + QMakeMetaInfo libinfo; debug_msg(1, "Processing PRL file: %s", meta_file.toLatin1().constData()); if (!libinfo.readLib(meta_file)) { fprintf(stderr, "Error processing meta file %s\n", meta_file.toLatin1().constData()); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 4b33713a75f..24215ae7b05 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -407,7 +407,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) const ProStringList &l = project->values("QMAKE_PRL_INTERNAL_FILES"); ProStringList::ConstIterator it; for(it = l.begin(); it != l.end(); ++it) { - QMakeMetaInfo libinfo(project); + QMakeMetaInfo libinfo; if (libinfo.readLib((*it).toQString()) && !libinfo.isEmpty("QMAKE_PRL_BUILD_DIR")) { ProString dir; int slsh = (*it).lastIndexOf(Option::dir_sep); diff --git a/qmake/meta.cpp b/qmake/meta.cpp index 2e8759b8ba0..c5c14d9b56b 100644 --- a/qmake/meta.cpp +++ b/qmake/meta.cpp @@ -35,13 +35,6 @@ QT_BEGIN_NAMESPACE QHash QMakeMetaInfo::cache_vars; -QMakeMetaInfo::QMakeMetaInfo(QMakeProject *_conf) - : conf(_conf) -{ - -} - - bool QMakeMetaInfo::readLib(const QString &meta_file) { diff --git a/qmake/meta.h b/qmake/meta.h index 4721085fd27..5f41a37df03 100644 --- a/qmake/meta.h +++ b/qmake/meta.h @@ -41,11 +41,9 @@ class QMakeProject; class QMakeMetaInfo { - QMakeProject *conf; ProValueMap vars; static QHash cache_vars; public: - QMakeMetaInfo(QMakeProject *_conf); // These functions expect the path to be normalized static QString checkLib(const QString &lib); From 6d049ad63d1044da2287f5736b9863323be2be0c Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 4 Apr 2019 16:33:59 +0200 Subject: [PATCH 06/12] Remove unused static method The only use of this method got removed already in commit bebae3737624. Change-Id: I9757cbe34710efd9a9d31c74f81e01da40453ff9 Reviewed-by: Thiago Macieira Reviewed-by: Joerg Bornemann --- src/corelib/io/qstandardpaths_win.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index 1809861fc6e..c2c3b2702bf 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -86,15 +86,6 @@ static void appendOrganizationAndApp(QString &path) // Courtesy qstandardpaths_u #endif } -static inline QString displayName(QStandardPaths::StandardLocation type) -{ -#ifndef QT_BOOTSTRAPPED - return QStandardPaths::displayName(type); -#else - return QString::number(type); -#endif -} - static inline void appendTestMode(QString &path) { if (QStandardPaths::isTestModeEnabled()) From bdee1189bf52a00fa89a8898e92bf75c36930666 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 3 Apr 2019 19:41:36 +0200 Subject: [PATCH 07/12] png handler: initialize all the variables passed to png_get_IHDR oss-fuzz found at least width is sometimes not initialized, and we're initializing almost all of them in most cases so be complete. the oss-fuzz instance was ==1==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x667c43 in operator!= /src/qtbase/src/corelib/tools/qsize.h:173:25 #1 0x667c43 in setup_qt /src/qtbase/src/gui/image/qpnghandler.cpp:403 Change-Id: Idb9aaf5ab85509d9c893beaf8d9118339ba46be7 Reviewed-by: Allan Sandfeld Jensen --- src/gui/image/qpnghandler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 808037f434e..801b30881dc 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -231,8 +231,8 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal if (screen_gamma != 0.0 && file_gamma != 0.0) png_set_gamma(png_ptr, 1.0f / screen_gamma, file_gamma); - png_uint_32 width; - png_uint_32 height; + png_uint_32 width = 0; + png_uint_32 height = 0; int bit_depth = 0; int color_type = 0; png_bytep trans_alpha = 0; @@ -240,7 +240,7 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal int num_trans; png_colorp palette = 0; int num_palette; - int interlace_method; + int interlace_method = PNG_INTERLACE_LAST; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0); png_set_interlace_handling(png_ptr); @@ -677,7 +677,7 @@ bool QPngHandlerPrivate::readPngImage(QImage *outImage) QImage::Format QPngHandlerPrivate::readImageFormat() { QImage::Format format = QImage::Format_Invalid; - png_uint_32 width, height; + png_uint_32 width = 0, height = 0; int bit_depth = 0, color_type = 0; png_colorp palette; int num_palette; From df7eec6bcb0b9fdee3888c9b4683dbb533eba300 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 3 Apr 2019 13:34:35 +0200 Subject: [PATCH 08/12] Windows QPA/File dialog: Refactor code copying non-file shell items Remove the canCopy() check which is not required and pass up the error message. Remove special characters and use the base name of the display name which can be an URL. Task-number: QTBUG-71785 Change-Id: I22966cb8d1f5bca0bbca71cf3ebe66e4ede1a747 Reviewed-by: Oliver Wolff Reviewed-by: Andre de la Rocha --- .../windows/qwindowsdialoghelpers.cpp | 90 +++++++++++++------ 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 1b17759b5f6..ba441a19214 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -569,12 +569,10 @@ public: bool isFileSystem() const { return (m_attributes & SFGAO_FILESYSTEM) != 0; } bool isDir() const { return (m_attributes & SFGAO_FOLDER) != 0; } - // Copy using IFileOperation - bool canCopy() const { return (m_attributes & SFGAO_CANCOPY) != 0; } // Supports IStream bool canStream() const { return (m_attributes & SFGAO_STREAM) != 0; } - bool copyData(QIODevice *out); + bool copyData(QIODevice *out, QString *errorMessage); static IShellItems itemsFromItemArray(IShellItemArray *items); @@ -666,14 +664,19 @@ QWindowsShellItem::IShellItems QWindowsShellItem::itemsFromItemArray(IShellItemA return result; } -bool QWindowsShellItem::copyData(QIODevice *out) +bool QWindowsShellItem::copyData(QIODevice *out, QString *errorMessage) { - if (!canCopy() || !canStream()) + if (!canStream()) { + *errorMessage = QLatin1String("Item not streamable"); return false; + } IStream *istream = nullptr; HRESULT hr = m_item->BindToHandler(nullptr, BHID_Stream, IID_PPV_ARGS(&istream)); - if (FAILED(hr)) + if (FAILED(hr)) { + *errorMessage = QLatin1String("BindToHandler() failed: ") + + QLatin1String(QWindowsContext::comErrorString(hr)); return false; + } enum : ULONG { bufSize = 102400 }; char buffer[bufSize]; ULONG bytesRead; @@ -686,7 +689,12 @@ bool QWindowsShellItem::copyData(QIODevice *out) break; } istream->Release(); - return hr == S_OK || hr == S_FALSE; + if (hr != S_OK && hr != S_FALSE) { + *errorMessage = QLatin1String("Read() failed: ") + + QLatin1String(QWindowsContext::comErrorString(hr)); + return false; + } + return true; } // Helper for "Libraries": collections of folders appearing from Windows 7 @@ -735,8 +743,6 @@ void QWindowsShellItem::format(QDebug &d) const d << " [dir]"; if (canStream()) d << " [stream]"; - if (canCopy()) - d << " [copyable]"; d << ", normalDisplay=\"" << normalDisplay() << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() << "\", urlString=\"" << urlString() << "\", fileSysPath=\"" << fileSysPath() << '"'; @@ -1395,21 +1401,50 @@ static void cleanupTemporaryItemCopies() QFile::remove(file); } -static QString createTemporaryItemCopy(QWindowsShellItem &qItem) -{ - if (!qItem.canCopy() || !qItem.canStream()) - return QString(); - QString pattern = qItem.normalDisplay(); - const int lastDot = pattern.lastIndexOf(QLatin1Char('.')); - const QString placeHolder = QStringLiteral("_XXXXXX"); - if (lastDot >= 0) - pattern.insert(lastDot, placeHolder); - else - pattern.append(placeHolder); +// Determine temporary file pattern from a shell item's display +// name. This can be a URL. - QTemporaryFile targetFile(QDir::tempPath() + QLatin1Char('/') + pattern); +static bool validFileNameCharacter(QChar c) +{ + return c.isLetterOrNumber() || c == QLatin1Char('_') || c == QLatin1Char('-'); +} + +QString tempFilePattern(QString name) +{ + const int lastSlash = qMax(name.lastIndexOf(QLatin1Char('/')), + name.lastIndexOf(QLatin1Char('\\'))); + if (lastSlash != -1) + name.remove(0, lastSlash + 1); + + int lastDot = name.lastIndexOf(QLatin1Char('.')); + if (lastDot < 0) + lastDot = name.size(); + name.insert(lastDot, QStringLiteral("_XXXXXX")); + + for (int i = lastDot - 1; i >= 0; --i) { + if (!validFileNameCharacter(name.at(i))) + name[i] = QLatin1Char('_'); + } + + name.prepend(QDir::tempPath() + QLatin1Char('/')); + return name; +} + +static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorMessage) +{ + if (!qItem.canStream()) { + *errorMessage = QLatin1String("Item not streamable"); + return QString(); + } + + QTemporaryFile targetFile(tempFilePattern(qItem.normalDisplay())); targetFile.setAutoRemove(false); - if (!targetFile.open() || !qItem.copyData(&targetFile)) + if (!targetFile.open()) { + *errorMessage = QLatin1String("Cannot create temporary file: ") + + targetFile.errorString(); + return QString(); + } + if (!qItem.copyData(&targetFile, errorMessage)) return QString(); const QString result = targetFile.fileName(); if (temporaryItemCopies()->isEmpty()) @@ -1427,11 +1462,14 @@ QList QWindowsNativeOpenFileDialog::dialogResult() const QWindowsShellItem qItem(item); const QString path = qItem.path(); if (path.isEmpty() && !qItem.isDir()) { - const QString temporaryCopy = createTemporaryItemCopy(qItem); - if (temporaryCopy.isEmpty()) - qWarning() << "Unable to create a local copy of" << qItem; - else + QString errorMessage; + const QString temporaryCopy = createTemporaryItemCopy(qItem, &errorMessage); + if (temporaryCopy.isEmpty()) { + qWarning().noquote() << "Unable to create a local copy of" << qItem + << ": " << errorMessage; + } else { result.append(QUrl::fromLocalFile(temporaryCopy)); + } } else { result.append(qItem.url()); } From 6ce2a87c23bbaacece7d32df276f64a0058e447d Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 26 Mar 2019 14:07:03 +0100 Subject: [PATCH 09/12] Forward declare all types required for compilation with `-trace` This patch fixes compilation with `-trace lttng` or `-trace etw`. We need to forward declare QEvent, QImageReader etc., otherwise the types will be unknown while compiling the trace points. In order to handle this generically, the tracegen utility is extended to support a 'prefix text' in the `*.tracepoints` input files. Any text within curly braces will be embedded as-is in the generated file. This can then be used to add forward declarations for the types we need, including potential namespaces and such. Change-Id: I5cb16763ce0fcb48ce3ea4577578d468ff3a4f4b Reviewed-by: Konstantin Tokarev --- src/corelib/qtcore.tracepoints | 6 ++++++ src/gui/qtgui.tracepoints | 6 ++++++ src/tools/tracegen/etw.cpp | 29 +++++++++++++++++------------ src/tools/tracegen/lttng.cpp | 19 ++++++++++++------- src/tools/tracegen/provider.cpp | 19 +++++++++++++++++++ src/tools/tracegen/provider.h | 1 + src/widgets/qtwidgets.tracepoints | 6 ++++++ 7 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/corelib/qtcore.tracepoints b/src/corelib/qtcore.tracepoints index 33734a42749..a9a08071f3b 100644 --- a/src/corelib/qtcore.tracepoints +++ b/src/corelib/qtcore.tracepoints @@ -1,3 +1,9 @@ +{ +QT_BEGIN_NAMESPACE +class QEvent; +QT_END_NAMESPACE +} + QCoreApplicationPrivate_init_entry() QCoreApplicationPrivate_init_exit() diff --git a/src/gui/qtgui.tracepoints b/src/gui/qtgui.tracepoints index aed6c35c03f..0a96a589b18 100644 --- a/src/gui/qtgui.tracepoints +++ b/src/gui/qtgui.tracepoints @@ -1,3 +1,9 @@ +{ +QT_BEGIN_NAMESPACE +class QImageReader; +QT_END_NAMESPACE +} + QGuiApplicationPrivate_init_entry() QGuiApplicationPrivate_init_exit() diff --git a/src/tools/tracegen/etw.cpp b/src/tools/tracegen/etw.cpp index 8c065f93c9e..e8391379155 100644 --- a/src/tools/tracegen/etw.cpp +++ b/src/tools/tracegen/etw.cpp @@ -110,19 +110,21 @@ static QString createGuid(const QUuid &uuid) return guid; } -static void writePrologue(QTextStream &stream, const QString &fileName, const QString &providerName) +static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider) { - QUuid uuid = QUuid::createUuidV5(QUuid(), providerName.toLocal8Bit()); + QUuid uuid = QUuid::createUuidV5(QUuid(), provider.name.toLocal8Bit()); - const QString provider = providerVar(providerName); + const QString providerV = providerVar(provider.name); const QString guard = includeGuard(fileName); const QString guid = createGuid(uuid); const QString guidString = uuid.toString(); stream << "#ifndef " << guard << "\n" << "#define " << guard << "\n" + << "\n" << "#include \n" - << "#include \n"; + << "#include \n" + << "\n"; /* TraceLogging API macros cannot deal with UTF8 * source files, so we work around it like this @@ -132,30 +134,33 @@ static void writePrologue(QTextStream &stream, const QString &fileName, const QS "#define _TlgPragmaUtf8Begin\n" "#define _TlgPragmaUtf8End\n"; - stream << qtHeaders(); - stream << "\n"; + stream << qtHeaders(); + stream << "\n"; + + if (!provider.prefixText.isEmpty()) + stream << provider.prefixText.join(QLatin1Char('\n')) << "\n\n"; stream << "#ifdef TRACEPOINT_DEFINE\n" << "/* " << guidString << " */\n" - << "TRACELOGGING_DEFINE_PROVIDER(" << provider << ", \"" - << providerName <<"\", " << guid << ");\n\n"; + << "TRACELOGGING_DEFINE_PROVIDER(" << providerV << ", \"" + << provider.name <<"\", " << guid << ");\n\n"; stream << "static inline void registerProvider()\n" << "{\n" - << " TraceLoggingRegister(" << provider << ");\n" + << " TraceLoggingRegister(" << providerV << ");\n" << "}\n\n"; stream << "static inline void unregisterProvider()\n" << "{\n" - << " TraceLoggingUnregister(" << provider << ");\n" + << " TraceLoggingUnregister(" << providerV << ");\n" << "}\n"; stream << "Q_CONSTRUCTOR_FUNCTION(registerProvider)\n" << "Q_DESTRUCTOR_FUNCTION(unregisterProvider)\n\n"; stream << "#else\n" - << "TRACELOGGING_DECLARE_PROVIDER(" << provider << ");\n" + << "TRACELOGGING_DECLARE_PROVIDER(" << providerV << ");\n" << "#endif // TRACEPOINT_DEFINE\n\n"; } @@ -224,7 +229,7 @@ void writeEtw(QFile &file, const Provider &provider) const QString fileName = QFileInfo(file.fileName()).fileName(); - writePrologue(stream, fileName, provider.name); + writePrologue(stream, fileName, provider); writeTracepoints(stream, provider); writeEpilogue(stream, fileName); } diff --git a/src/tools/tracegen/lttng.cpp b/src/tools/tracegen/lttng.cpp index 5d41bf5f1f6..f0fbca9e16f 100644 --- a/src/tools/tracegen/lttng.cpp +++ b/src/tools/tracegen/lttng.cpp @@ -104,17 +104,22 @@ static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) } } -static void writePrologue(QTextStream &stream, const QString &fileName, const QString &providerName) +static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider) { - stream << "#undef TRACEPOINT_PROVIDER\n"; - stream << "#define TRACEPOINT_PROVIDER " << providerName << "\n\n"; - - stream << qtHeaders(); - const QString guard = includeGuard(fileName); + stream << "#undef TRACEPOINT_PROVIDER\n"; + stream << "#define TRACEPOINT_PROVIDER " << provider.name << "\n"; stream << "\n"; + // include prefix text or qt headers only once + stream << "#if !defined(" << guard << ")\n"; + stream << qtHeaders(); + stream << "\n"; + if (!provider.prefixText.isEmpty()) + stream << provider.prefixText.join(QLatin1Char('\n')) << "\n\n"; + stream << "#endif\n\n"; + /* the first guard is the usual one, the second is required * by LTTNG to force the re-evaluation of TRACEPOINT_* macros */ @@ -213,7 +218,7 @@ void writeLttng(QFile &file, const Provider &provider) const QString fileName = QFileInfo(file.fileName()).fileName(); - writePrologue(stream, fileName, provider.name); + writePrologue(stream, fileName, provider); writeTracepoints(stream, provider); writeEpilogue(stream, fileName); } diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp index a6523a2e3d2..39633efe5d8 100644 --- a/src/tools/tracegen/provider.cpp +++ b/src/tools/tracegen/provider.cpp @@ -275,9 +275,21 @@ Provider parseProvider(const QString &filename) Provider provider; provider.name = QFileInfo(filename).baseName(); + bool parsingPrefixText = false; for (int lineNumber = 1; !s.atEnd(); ++lineNumber) { QString line = s.readLine().trimmed(); + if (line == QLatin1String("{")) { + parsingPrefixText = true; + continue; + } else if (parsingPrefixText && line == QLatin1String("}")) { + parsingPrefixText = false; + continue; + } else if (parsingPrefixText) { + provider.prefixText.append(line); + continue; + } + if (line.isEmpty() || line.startsWith(QLatin1Char('#'))) continue; @@ -296,7 +308,14 @@ Provider parseProvider(const QString &filename) } } + if (parsingPrefixText) { + panic("Syntax error while processing '%s': " + "no closing brace found for prefix text block", + qPrintable(filename)); + } + #ifdef TRACEGEN_DEBUG + qDebug() << provider.prefixText; for (auto i = provider.tracepoints.constBegin(); i != provider.tracepoints.constEnd(); ++i) dumpTracepoint(*i); #endif diff --git a/src/tools/tracegen/provider.h b/src/tools/tracegen/provider.h index 9771e62f4d9..9be0c33d890 100644 --- a/src/tools/tracegen/provider.h +++ b/src/tools/tracegen/provider.h @@ -86,6 +86,7 @@ struct Provider { QString name; QVector tracepoints; + QStringList prefixText; }; Provider parseProvider(const QString &filename); diff --git a/src/widgets/qtwidgets.tracepoints b/src/widgets/qtwidgets.tracepoints index 01a13836703..bfaf87ffcca 100644 --- a/src/widgets/qtwidgets.tracepoints +++ b/src/widgets/qtwidgets.tracepoints @@ -1,3 +1,9 @@ +{ +QT_BEGIN_NAMESPACE +class QEvent; +QT_END_NAMESPACE +} + QApplication_notify_entry(QObject *receiver, QEvent *event, int type) QApplication_notify_event_filtered(QObject *receiver, QEvent *event, int type) QApplication_notify_before_delivery(QObject *receiver, QEvent *event, int type) From 5f62202e6c89269da3e9faaea4c88d0f19416cc1 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 26 Mar 2019 15:23:48 +0100 Subject: [PATCH 10/12] Add tracepoint to qt_message_print This allows us to deduce a lot about what a Qt application is doing, since the debug output usually contains a lot of information. Change-Id: I28a18afd151a1640a44ba8c7c9cd87d5d66c99b0 Reviewed-by: Christoph Sterz Reviewed-by: Thiago Macieira --- src/corelib/global/qlogging.cpp | 3 +++ src/corelib/qtcore.tracepoints | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 168934c2028..30232170fb1 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -57,6 +57,7 @@ #include "private/qloggingregistry_p.h" #include "private/qcoreapplication_p.h" #include "private/qsimd_p.h" +#include #endif #ifdef Q_OS_WIN #include @@ -1811,6 +1812,8 @@ static void ungrabMessageHandler() { } static void qt_message_print(QtMsgType msgType, const QMessageLogContext &context, const QString &message) { #ifndef QT_BOOTSTRAPPED + Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message); + // qDebug, qWarning, ... macros do not check whether category is enabled if (isDefaultCategory(context.category)) { if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) { diff --git a/src/corelib/qtcore.tracepoints b/src/corelib/qtcore.tracepoints index a9a08071f3b..f9018acdbf9 100644 --- a/src/corelib/qtcore.tracepoints +++ b/src/corelib/qtcore.tracepoints @@ -38,3 +38,5 @@ QMetaObject_activate_begin_slot_functor(void *slotObject) QMetaObject_activate_end_slot_functor(void *slotObject) QMetaObject_activate_begin_declarative_signal(QObject *sender, int signalIndex) QMetaObject_activate_end_declarative_signal(QObject *sender, int signalIndex) + +qt_message_print(int type, const char *category, const char *function, const char *file, int line, const QString &message) From 127518deda5a05fda2ce24be98aaaeb7b975f163 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 27 Mar 2019 13:56:57 +0100 Subject: [PATCH 11/12] Introduce Q_TRACE_SCOPE to simplify tracing of a function entry/exit Additionally, we also add a Q_TRACE_EXIT which runs a trace point when the scope is exited, leveraging qScopeGuard behind the scenes. Q_TRACE_SCOPE uses Q_TRACE_EXIT internally - the difference is that the _SCOPE version enforces the naming scheme of _entry / _exit for the tracepoints, whereas Q_TRACE_EXIT can be used generically. Change-Id: I4a2f5ea09f451fcf664d07fd493b679f7527ac06 Reviewed-by: Thiago Macieira --- src/corelib/global/qtrace_p.h | 17 ++++++++++++++++- src/corelib/kernel/qcoreapplication.cpp | 4 +--- src/gui/kernel/qguiapplication.cpp | 8 ++------ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/corelib/global/qtrace_p.h b/src/corelib/global/qtrace_p.h index 3d04a7311d4..20f2beac986 100644 --- a/src/corelib/global/qtrace_p.h +++ b/src/corelib/global/qtrace_p.h @@ -52,11 +52,18 @@ // /* - * The Qt tracepoints API consists of only three macros: + * The Qt tracepoints API consists of only five macros: * * - Q_TRACE(tracepoint, args...) * Fires 'tracepoint' if it is enabled. * + * - Q_TRACE_EXIT(tracepoint, args...) + * Fires 'tracepoint' if it is enabled when the current scope exists. + * + * - Q_TRACE_SCOPE(tracepoint, args...) + * Wrapper around Q_TRACE/_EXIT to trace entry and exit. First it traces + * `${tracepoint}_entry` and then `${tracepoint}_exit` on scope exit. + * * - Q_UNCONDITIONAL_TRACE(tracepoint, args...) * Fires 'tracepoint' unconditionally: no check is performed to query * whether 'tracepoint' is enabled. @@ -110,15 +117,23 @@ */ #include +#include QT_BEGIN_NAMESPACE #if defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED) # define Q_TRACE(x, ...) QtPrivate::trace_ ## x(__VA_ARGS__) +# define Q_TRACE_EXIT(x, ...) \ + const auto qTraceExit_ ## x ## __COUNTER__ = qScopeGuard([&]() { Q_TRACE(x, __VA_ARGS__); }); +# define Q_TRACE_SCOPE(x, ...) \ + Q_TRACE(x ## _entry, __VA_ARGS__); \ + Q_TRACE_EXIT(x ## _exit, __VA_ARGS__); # define Q_UNCONDITIONAL_TRACE(x, ...) QtPrivate::do_trace_ ## x(__VA_ARGS__) # define Q_TRACE_ENABLED(x) QtPrivate::trace_ ## x ## _enabled() #else # define Q_TRACE(x, ...) +# define Q_TRACE_EXIT(x, ...) +# define Q_TRACE_SCOPE(x, ...) # define Q_UNCONDITIONAL_TRACE(x, ...) # define Q_TRACE_ENABLED(x) false #endif // defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 6d7985c91bf..d173ec029bb 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -778,7 +778,7 @@ QCoreApplication::QCoreApplication(int &argc, char **argv void QCoreApplicationPrivate::init() { - Q_TRACE(QCoreApplicationPrivate_init_entry); + Q_TRACE_SCOPE(QCoreApplicationPrivate_init); #if defined(Q_OS_MACOS) QMacAutoReleasePool pool; @@ -883,8 +883,6 @@ void QCoreApplicationPrivate::init() #ifndef QT_NO_QOBJECT is_app_running = true; // No longer starting up. #endif - - Q_TRACE(QCoreApplicationPrivate_init_exit); } /*! diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index fd01f8bb7b2..424af20f26a 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1421,7 +1421,7 @@ void QGuiApplicationPrivate::eventDispatcherReady() void QGuiApplicationPrivate::init() { - Q_TRACE(QGuiApplicationPrivate_init_entry); + Q_TRACE_SCOPE(QGuiApplicationPrivate_init); #if defined(Q_OS_MACOS) QMacAutoReleasePool pool; @@ -1585,8 +1585,6 @@ void QGuiApplicationPrivate::init() if (!QGuiApplicationPrivate::displayName) QObject::connect(q, &QGuiApplication::applicationNameChanged, q, &QGuiApplication::applicationDisplayNameChanged); - - Q_TRACE(QGuiApplicationPrivate_init_exit); } extern void qt_cleanupFontDatabase(); @@ -1830,7 +1828,7 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) { - Q_TRACE(QGuiApplicationPrivate_processWindowSystemEvent_entry, e->type); + Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type); switch(e->type) { case QWindowSystemInterfacePrivate::Mouse: @@ -1940,8 +1938,6 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv qWarning() << "Unknown user input event type:" << e->type; break; } - - Q_TRACE(QGuiApplicationPrivate_processWindowSystemEvent_exit, e->type); } /*! \internal From f4c41b9797f08f173049502fa7bd465cf5bde938 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 27 Mar 2019 14:00:21 +0100 Subject: [PATCH 12/12] Add missing _exit tracepoints for event handling This allows tools that look for matching `foo_entry/exit` pairs in the trace data to work properly. An unmatched `_entry` would otherwise confuse them, making them think that the call stack is continuously increasing. Change-Id: Idff7f587ea25c46ec86ad623cc82d503db34a194 Reviewed-by: Christoph Sterz Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication.cpp | 4 ++-- src/corelib/qtcore.tracepoints | 2 ++ src/widgets/kernel/qapplication.cpp | 2 +- src/widgets/qtwidgets.tracepoints | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index d173ec029bb..596941b5a9a 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1197,7 +1197,7 @@ bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) { // Note: when adjusting the tracepoints in here // consider adjusting QApplicationPrivate::notify_helper too. - Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type()); + Q_TRACE_SCOPE(QCoreApplication_notify, receiver, event, event->type()); // send to all application event filters (only does anything in the main thread) if (QCoreApplication::self @@ -1489,7 +1489,7 @@ bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) */ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) { - Q_TRACE(QCoreApplication_postEvent_entry, receiver, event, event->type()); + Q_TRACE_SCOPE(QCoreApplication_postEvent, receiver, event, event->type()); if (receiver == 0) { qWarning("QCoreApplication::postEvent: Unexpected null receiver"); diff --git a/src/corelib/qtcore.tracepoints b/src/corelib/qtcore.tracepoints index f9018acdbf9..3a70136741b 100644 --- a/src/corelib/qtcore.tracepoints +++ b/src/corelib/qtcore.tracepoints @@ -16,6 +16,7 @@ QEvent_ctor(QEvent *event, int type) QEvent_dtor(QEvent *event, int type) QCoreApplication_postEvent_entry(QObject *receiver, QEvent *event, int type) +QCoreApplication_postEvent_exit(QObject *receiver, QEvent *event, int type) QCoreApplication_postEvent_event_compressed(QObject *receiver, QEvent *event) QCoreApplication_postEvent_event_posted(QObject *receiver, QEvent *event, int type) @@ -23,6 +24,7 @@ QCoreApplication_sendEvent(QObject *receiver, QEvent *event, int type) QCoreApplication_sendSpontaneousEvent(QObject *receiver, QEvent *event, int type) QCoreApplication_notify_entry(QObject *receiver, QEvent *event, int type) +QCoreApplication_notify_exit(QObject *receiver, QEvent *event, int type) QCoreApplication_notify_event_filtered(QObject *receiver, QEvent *event, int type) QCoreApplication_notify_before_delivery(QObject *receiver, QEvent *event, int type) QCoreApplication_notify_after_delivery(QObject *receiver, QEvent *event, int type, bool consumed) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index ebab87b1935..fdece8414cf 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3697,7 +3697,7 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) // to the ones in QCoreApplicationPrivate::notify_helper; the reason for their // duplication is because tracepoint symbols are not exported by QtCore. // If you adjust the tracepoints here, consider adjusting QCoreApplicationPrivate too. - Q_TRACE(QApplication_notify_entry, receiver, e, e->type()); + Q_TRACE_SCOPE(QApplication_notify, receiver, e, e->type()); // send to all application event filters if (threadRequiresCoreApplication() diff --git a/src/widgets/qtwidgets.tracepoints b/src/widgets/qtwidgets.tracepoints index bfaf87ffcca..9c40cdb3e79 100644 --- a/src/widgets/qtwidgets.tracepoints +++ b/src/widgets/qtwidgets.tracepoints @@ -5,6 +5,7 @@ QT_END_NAMESPACE } QApplication_notify_entry(QObject *receiver, QEvent *event, int type) +QApplication_notify_exit(QObject *receiver, QEvent *event, int type) QApplication_notify_event_filtered(QObject *receiver, QEvent *event, int type) QApplication_notify_before_delivery(QObject *receiver, QEvent *event, int type) QApplication_notify_after_delivery(QObject *receiver, QEvent *event, int type, bool consumed)