From d9a2dd8d3b55d16d2e38d124abb0ade490963b37 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Jan 2017 12:17:12 -0800 Subject: [PATCH 01/85] QDir::mkpath: don't try to mkdir in automount filesystems Automount filesystems like /home on many operating systems (QNX and OpenIndiana, at least) don't like if you try to mkdir in them, even if the file path already exists. OpenIndiana even gives you an ENOSYS error. So instead, let's try to mkdir our target, if we fail because of ENOENT, we try to create the parent, then try again. Task-number: QTBUG-58390 Change-Id: Ibe5b1b60c6ea47e19612fffd149cce81589b0acd Reviewed-by: James McDonnell Reviewed-by: David Faure --- src/corelib/io/qfilesystemengine_unix.cpp | 98 +++++++++++++++-------- tests/auto/corelib/io/qdir/tst_qdir.cpp | 2 +- 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 1b908eac55e..96829b3b031 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -556,45 +556,75 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM return data.hasFlags(what); } +// Note: if \a shouldMkdirFirst is false, we assume the caller did try to mkdir +// before calling this function. +static bool createDirectoryWithParents(const QByteArray &nativeName, bool shouldMkdirFirst = true) +{ + // helper function to check if a given path is a directory, since mkdir can + // fail if the dir already exists (it may have been created by another + // thread or another process) + const auto isDir = [](const QByteArray &nativeName) { + QT_STATBUF st; + return QT_STAT(nativeName.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR; + }; + + if (shouldMkdirFirst && QT_MKDIR(nativeName, 0777) == 0) + return true; + if (errno == EEXIST) + return isDir(nativeName); + if (errno != ENOENT) + return false; + + // mkdir failed because the parent dir doesn't exist, so try to create it + int slash = nativeName.lastIndexOf('/'); + if (slash < 1) + return false; + + QByteArray parentNativeName = nativeName.left(slash); + if (!createDirectoryWithParents(parentNativeName)) + return false; + + // try again + if (QT_MKDIR(nativeName, 0777) == 0) + return true; + return errno == EEXIST && isDir(nativeName); +} + //static bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) { QString dirName = entry.filePath(); - if (createParents) { - dirName = QDir::cleanPath(dirName); - for (int oldslash = -1, slash=0; slash != -1; oldslash = slash) { - slash = dirName.indexOf(QDir::separator(), oldslash+1); - if (slash == -1) { - if (oldslash == dirName.length()) - break; - slash = dirName.length(); - } - if (slash) { - const QByteArray chunk = QFile::encodeName(dirName.left(slash)); - if (QT_MKDIR(chunk.constData(), 0777) != 0) { - if (errno == EEXIST -#if defined(Q_OS_QNX) - // On QNX the QNet (VFS paths of other hosts mounted under a directory - // such as /net) mountpoint returns ENOENT, despite existing. stat() - // on the QNet mountpoint returns successfully and reports S_IFDIR. - || errno == ENOENT -#endif - ) { - QT_STATBUF st; - if (QT_STAT(chunk.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) - continue; - } - return false; - } - } - } - return true; - } -#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s - if (dirName.endsWith(QLatin1Char('/'))) + + // Darwin doesn't support trailing /'s, so remove for everyone + while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/'))) dirName.chop(1); -#endif - return (QT_MKDIR(QFile::encodeName(dirName).constData(), 0777) == 0); + + // try to mkdir this directory + QByteArray nativeName = QFile::encodeName(dirName); + if (QT_MKDIR(nativeName, 0777) == 0) + return true; + if (!createParents) + return false; + + // we need the cleaned path in order to create the parents + // and we save errno just in case encodeName needs to load codecs + int savedErrno = errno; + bool pathChanged; + { + QString cleanName = QDir::cleanPath(dirName); + + // Check if the cleaned name is the same or not. If we were given a + // path with resolvable "../" sections, cleanPath will remove them, but + // this may change the target dir if one of those segments was a + // symlink. This operation depends on cleanPath's optimization of + // returning the original string if it didn't modify anything. + pathChanged = !dirName.isSharedWith(cleanName); + if (pathChanged) + nativeName = QFile::encodeName(cleanName); + } + + errno = savedErrno; + return createDirectoryWithParents(nativeName, pathChanged); } //static diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index b86c6e4dfaa..c3774997e99 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -350,7 +350,7 @@ void tst_QDir::mkdir_data() << QDir::currentPath() + "/testdir/two/three"; QTest::newRow("data0") << dirs.at(0) << true; QTest::newRow("data1") << dirs.at(1) << false; - QTest::newRow("data2") << dirs.at(2) << false; + QTest::newRow("data2") << dirs.at(2) << false; // note: requires data1 to have been run! // Ensure that none of these directories already exist QDir dir; From d9c3d2301dba6922e10d8509b220a795686e8fa9 Mon Sep 17 00:00:00 2001 From: Oleg Yadrov Date: Tue, 10 Jan 2017 15:49:54 -0800 Subject: [PATCH 02/85] macOS: use active window device pixel ratio for drag pixmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In QCocoaDrag::dragPixmap, it treats QDrag::source as a QWindow, but it is not - it's just a generic QObject* of some kind (which QQuickDrag sets to the originating QQuickItem, and the widgets stack sets to a QWidget). This failure means that dpr stayed at 1.0. Unfortunately it’s not possible to receive a pointer on QWindow directly from QQuickItem because QtWidgets and QtQuick do not share the sources, but we can use the same dpr as current focused window has because drag can only start from active window - press on a window which is not focused should activate it first. Task-number: QTBUG-57942 Change-Id: Id358c181d03d519188caaa83fb4226033b8ed1ea Reviewed-by: Tor Arne Vestbø Reviewed-by: Robin Burchell --- src/plugins/platforms/cocoa/qcocoadrag.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 7d11023b78d..a0967750e74 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -201,6 +201,10 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const dpr = sourceWindow->devicePixelRatio(); } #endif + else { + if (const QWindow *focusWindow = qApp->focusWindow()) + dpr = focusWindow->devicePixelRatio(); + } pm = QPixmap(width * dpr, height * dpr); pm.setDevicePixelRatio(dpr); QPainter p(&pm); From 0e3d6fe4f69955bf98e23a382caf5251e2b47ea0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 17 Feb 2017 00:54:04 +0100 Subject: [PATCH 03/85] QVarLengthArray: fix appending an already-contained item Like the lvalue QVector::append() overload, when we reallocate, we need to take a copy of the function's argument because the reference will get stale upon reallocation. Add a test. [ChangeLog][QtCore][QVarLengthArray] Fixed a bug involving appending an item already in the container to the container again. Change-Id: I06eeed6cb383dd5924e47a302bb3d1666d04c8e8 Reviewed-by: Thiago Macieira --- src/corelib/tools/qvarlengtharray.h | 20 ++++++++++++++----- .../qvarlengtharray/tst_qvarlengtharray.cpp | 17 ++++++++++++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index bb5ae78d2b3..2d3c25a5dd5 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -146,15 +146,25 @@ public: T value(int i, const T &defaultValue) const; inline void append(const T &t) { - if (s == a) // i.e. s != 0 + if (s == a) { // i.e. s != 0 + T copy(t); realloc(s, s<<1); - const int idx = s++; - if (QTypeInfo::isComplex) { - new (ptr + idx) T(t); + const int idx = s++; + if (QTypeInfo::isComplex) { + new (ptr + idx) T(std::move(copy)); + } else { + ptr[idx] = std::move(copy); + } } else { - ptr[idx] = t; + const int idx = s++; + if (QTypeInfo::isComplex) { + new (ptr + idx) T(t); + } else { + ptr[idx] = t; + } } } + void append(const T *buf, int size); inline QVarLengthArray &operator<<(const T &t) { append(t); return *this; } diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 7fc44343a51..0806ad13185 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -77,8 +77,21 @@ struct Foo void tst_QVarLengthArray::append() { - QVarLengthArray v; - v.append(QString("hello")); + QVarLengthArray v; + v.append(QString("1")); + v.append(v.front()); + QCOMPARE(v.capacity(), 2); + // transition from prealloc to heap: + v.append(v.front()); + QVERIFY(v.capacity() > 2); + QCOMPARE(v.front(), v.back()); + while (v.size() < v.capacity()) + v.push_back(v[0]); + QCOMPARE(v.back(), v.front()); + QCOMPARE(v.size(), v.capacity()); + // transition from heap to larger heap: + v.push_back(v.front()); + QCOMPARE(v.back(), v.front()); QVarLengthArray v2; // rocket! v2.append(5); From dd7f62059c2ae52b5c05fdbe1b6b5d5fa5bc1b03 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 16 Feb 2017 15:52:00 +0100 Subject: [PATCH 04/85] Fix a race in QFreeList The _next variable need the acquire and release fence in next() to synchronize with the equivalent operations in release() (which already have the them) The ordering on the _v[block] is not enough as this does not synchronize the same object. Task-number: QTBUG-58917 Change-Id: I17cc39e6791433348b6227363dbea92bcf03700d Reviewed-by: David Faure Reviewed-by: Thiago Macieira --- src/corelib/tools/qfreelist_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index c3efc41d62b..a8d1132d06d 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -237,7 +237,7 @@ inline int QFreeList::next() int id, newid, at; ElementType *v; do { - id = _next.load(); + id = _next.loadAcquire(); at = id & ConstantsType::IndexMask; const int block = blockfor(at); @@ -254,7 +254,7 @@ inline int QFreeList::next() } newid = v[at].next.load() | (id & ~ConstantsType::IndexMask); - } while (!_next.testAndSetRelaxed(id, newid)); + } while (!_next.testAndSetRelease(id, newid)); // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", // id & ConstantsType::IndexMask, // newid & ConstantsType::IndexMask, From 1d6700171cf41c17983edff285c3658933610523 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 7 Feb 2017 16:18:18 +0100 Subject: [PATCH 05/85] Respect XDG_CONFIG_HOME when getting ibus socket location Task-number: QTBUG-58687 Change-Id: I97ea8b7d7caf922227a92348fb914aead1ecd312 Reviewed-by: Tinu Weber Reviewed-by: Takao Fujiwara Reviewed-by: Konstantin Tokarev Reviewed-by: Shawn Rutledge --- .../platforminputcontexts/ibus/qibusplatforminputcontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 736c66ebc08..0a55f689c63 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -572,7 +572,8 @@ QString QIBusPlatformInputContextPrivate::getSocketPath() if (debug) qDebug() << "host=" << host << "displayNumber" << displayNumber; - return QDir::homePath() + QLatin1String("/.config/ibus/bus/") + + return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + + QLatin1String("/ibus/bus/") + QLatin1String(QDBusConnection::localMachineId()) + QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber); } From c5e687895dd2eba3106f697b6e92b84683402403 Mon Sep 17 00:00:00 2001 From: Eric Lemanissier Date: Mon, 16 Jan 2017 12:22:43 +0100 Subject: [PATCH 06/85] Adapt to the C++ SIC introduced by P0012: noexcept overloading see 5a1b4832a2 for more detail Task-number: QTBUG-58142 Change-Id: I51851ea9b4fe7b8eeadc452bc3dbb1ea00026d29 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/concurrent/qtconcurrentfunctionwrappers.h | 84 ++++++++++++++ .../qtconcurrentmap/qtconcurrentmap.pro | 3 + .../qtconcurrentmap/tst_qtconcurrentmap.cpp | 74 +++++++++++++ .../qtconcurrentrun/qtconcurrentrun.pro | 3 + .../qtconcurrentrun/tst_qtconcurrentrun.cpp | 104 ++++++++++++++++++ 5 files changed, 268 insertions(+) diff --git a/src/concurrent/qtconcurrentfunctionwrappers.h b/src/concurrent/qtconcurrentfunctionwrappers.h index a08be691237..111933410bc 100644 --- a/src/concurrent/qtconcurrentfunctionwrappers.h +++ b/src/concurrent/qtconcurrentfunctionwrappers.h @@ -192,6 +192,32 @@ QtConcurrent::ConstMemberFunctionWrapper createFunctionWrapper(T (C::*func return QtConcurrent::ConstMemberFunctionWrapper(func); } +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +QtConcurrent::FunctionWrapper1 createFunctionWrapper(T (*func)(U) noexcept) +{ + return QtConcurrent::FunctionWrapper1(func); +} + +template +QtConcurrent::MemberFunctionWrapper createFunctionWrapper(T (C::*func)() noexcept) +{ + return QtConcurrent::MemberFunctionWrapper(func); +} + +template +QtConcurrent::MemberFunctionWrapper1 createFunctionWrapper(T (C::*func)(U) noexcept) +{ + return QtConcurrent::MemberFunctionWrapper1(func); +} + +template +QtConcurrent::ConstMemberFunctionWrapper createFunctionWrapper(T (C::*func)() const noexcept) +{ + return QtConcurrent::ConstMemberFunctionWrapper(func); +} +#endif + struct PushBackWrapper { typedef void result_type; @@ -231,6 +257,20 @@ struct ReduceResultType typedef C ResultType; }; +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +struct ReduceResultType +{ + typedef U ResultType; +}; + +template +struct ReduceResultType +{ + typedef C ResultType; +}; +#endif + template struct MapResultType { @@ -249,6 +289,20 @@ struct MapResultType typedef T ResultType; }; +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +struct MapResultType +{ + typedef U ResultType; +}; + +template +struct MapResultType +{ + typedef T ResultType; +}; +#endif + #ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS template