From 1440c13c8c1ed8eaa99c5d5edbd6fa61fd5eee8b Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 10 Dec 2015 11:37:59 +0100 Subject: Check if the file is writable even while QT_BOOTSTRAPPED QConfFile::isWritable() has the extra effect that it will try and create the path where the file should be if it does not already exist. So this cannot be omitted as 'qmake -set' may be used in a situation where the path does not yet exist. Change-Id: I0113644259f78d090a0687c44cf60d400be9c859 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qsettings.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 413f5693f0..52bcb153ae 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1383,13 +1383,17 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo) Concurrent read and write are not a problem because the writing operation is atomic. */ QLockFile lockFile(confFile->name + QLatin1String(".lock")); +#endif if (!readOnly) { - if (!confFile->isWritable() || !lockFile.lock() ) { + if (!confFile->isWritable() +#ifndef QT_BOOTSTRAPPED + || !lockFile.lock() +#endif + ) { setStatus(QSettings::AccessError); return; } } -#endif /* We hold the lock. Let's reread the file if it has changed -- cgit v1.2.3 From b2c7c489ab40efb1f2f64aba5b90f5f4fb8d8536 Mon Sep 17 00:00:00 2001 From: David Fries Date: Tue, 24 Nov 2015 17:29:59 -0600 Subject: QLockFile: decide on locking strategy per path It is filesystem dependent if flock and fcntl locks are independent or the same underlying lock (which causes getting the second lock to fail). A temporary file in /tmp might be on a local file system and pass while the lock file is placed on NFS and fail with: setNativeLocks failed: Resource temporarily unavailable Instead check for lock conflicts per path and cache the result. Change-Id: I39c59bb240cd99ef0a0ec271243770ffd5df8a7d Reviewed-by: David Faure --- src/corelib/io/qlockfile_p.h | 2 +- src/corelib/io/qlockfile_unix.cpp | 42 +++++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h index 168062f467..48b642abd0 100644 --- a/src/corelib/io/qlockfile_p.h +++ b/src/corelib/io/qlockfile_p.h @@ -78,7 +78,7 @@ public: static QString processNameByPid(qint64 pid); #ifdef Q_OS_UNIX - static int checkFcntlWorksAfterFlock(); + static int checkFcntlWorksAfterFlock(const QString &fn); #endif QString fileName; diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index bd9f8a5988..667b108ba0 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -39,6 +39,10 @@ #include "QtCore/qfileinfo.h" #include "QtCore/qdebug.h" #include "QtCore/qdatetime.h" +#include "QtCore/qfileinfo.h" +#include "QtCore/qcache.h" +#include "QtCore/qglobalstatic.h" +#include "QtCore/qmutex.h" #include "private/qcore_unix_p.h" // qt_safe_open #include "private/qabstractfileengine_p.h" @@ -89,10 +93,10 @@ static qint64 qt_write_loop(int fd, const char *data, qint64 len) return pos; } -int QLockFilePrivate::checkFcntlWorksAfterFlock() +int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn) { #ifndef QT_NO_TEMPORARYFILE - QTemporaryFile file; + QTemporaryFile file(fn); if (!file.open()) return 0; const int fd = file.d_func()->engine()->handle(); @@ -114,24 +118,34 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock() #endif } -static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1); +// Cache the result of checkFcntlWorksAfterFlock for each directory a lock +// file is created in because in some filesystems, like NFS, both locks +// are the same. This does not take into account a filesystem changing. +// QCache is set to hold a maximum of 10 entries, this is to avoid unbounded +// growth, this is caching directories of files and it is assumed a low number +// will be sufficient. +typedef QCache CacheType; +Q_GLOBAL_STATIC_WITH_ARGS(CacheType, fcntlOK, (10)); +static QBasicMutex fcntlLock; /*! \internal Checks that the OS isn't using POSIX locks to emulate flock(). OS X is one of those. */ -static bool fcntlWorksAfterFlock() +static bool fcntlWorksAfterFlock(const QString &fn) { - int value = fcntlOK.load(); - if (Q_UNLIKELY(value == -1)) { - value = QLockFilePrivate::checkFcntlWorksAfterFlock(); - fcntlOK.store(value); + QMutexLocker lock(&fcntlLock); + bool *worksPtr = fcntlOK->object(fn); + if (!worksPtr) { + worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn)); + fcntlOK->insert(fn, worksPtr); } - return value == 1; + + return *worksPtr; } -static bool setNativeLocks(int fd) +static bool setNativeLocks(const QString &fileName, int fd) { #if defined(LOCK_EX) && defined(LOCK_NB) if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs @@ -143,8 +157,10 @@ static bool setNativeLocks(int fd) flockData.l_start = 0; flockData.l_len = 0; // 0 = entire file flockData.l_pid = getpid(); - if (fcntlWorksAfterFlock() && fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems + if (fcntlWorksAfterFlock(QDir::cleanPath(QFileInfo(fileName).absolutePath()) + QString('/')) + && fcntl(fd, F_SETLK, &flockData) == -1) { // for networked filesystems return false; + } return true; } @@ -171,7 +187,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys() } } // Ensure nobody else can delete the file while we have it - if (!setNativeLocks(fd)) { + if (!setNativeLocks(fileName, fd)) { const int errnoSaved = errno; qWarning() << "setNativeLocks failed:" << qt_error_string(errnoSaved); } @@ -195,7 +211,7 @@ bool QLockFilePrivate::removeStaleLock() const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644); if (fd < 0) // gone already? return false; - bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0); + bool success = setNativeLocks(fileName, fd) && (::unlink(lockFileName) == 0); close(fd); return success; } -- cgit v1.2.3 From e96fa5a780665e24fe4710868e399b3216a5d3b3 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 21 Dec 2015 11:37:49 +0100 Subject: Fix timeout calculations using qt_subtract_from_timeout Commit ed0c0070 introduced qt_subtract_from_timeout but used it incorrectly in several places. Change-Id: I80ea16088707929a45d5a61ec6f3370f8e63d1cd Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwinoverlappedionotifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp index c6ce15c2c9..8b7d70cf71 100644 --- a/src/corelib/io/qwinoverlappedionotifier.cpp +++ b/src/corelib/io/qwinoverlappedionotifier.cpp @@ -364,7 +364,7 @@ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped return false; if (triggeredOverlapped == overlapped) return true; - msecs = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); + t = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); if (t == 0) return false; } -- cgit v1.2.3 From 655246969eaa916fbc098a7315dc24830f5b8b5d Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Mon, 28 Dec 2015 11:43:36 +0100 Subject: forkfd: Also define BSD visibility macros in forkfd_qt.cpp. This is a follow-up to c8c4ad0 ("forkfd: Define __BSD_VISIBLE and _NETBSD_SOURCE"). Defining those macros in forkfd.c is not enough: forkfd_qt.cpp also sets _POSIX_C_SOURCE, and sys/cdefs.h can be included implicitly via Qt's headers ( ends up pulling unistd.h that leads to sys/cdefs.h and sys/types.h with both libstdc++ and older libc++ versions). In this case, __BSD_VISIBLE/_NETBSD_SOURCE are not defined, _POSIX_C_SOURCE is, several type definitions are omitted and by the time we include sys/time.h in forkfd.c the build fails. On FreeBSD < 11, the error looks like this: In file included from io/../../3rdparty/forkfd/forkfd.c:36, from io/forkfd_qt.cpp:80: /usr/include/sys/time.h:94: error: 'u_int' has not been declared Change-Id: I01fa2f5861027d99936d3026faeee9f0db3ecabd Reviewed-by: Thiago Macieira --- src/corelib/io/forkfd_qt.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/corelib/io') diff --git a/src/corelib/io/forkfd_qt.cpp b/src/corelib/io/forkfd_qt.cpp index 6704ec6f2a..d282c08fbd 100644 --- a/src/corelib/io/forkfd_qt.cpp +++ b/src/corelib/io/forkfd_qt.cpp @@ -39,6 +39,15 @@ # define _XOPEN_SOURCE 700 #endif +// Define BSD visibility macros. These are also defined in forkfd.c, but the +// headers using them may be included before forkfd.c itself. +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +#ifndef __BSD_VISIBLE +# define __BSD_VISIBLE 1 +#endif + #include #include "qprocess_p.h" -- cgit v1.2.3 From b4ab4868bc8422e09590d13d35c2bba7a195ccf5 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 6 Jan 2016 12:58:56 +0100 Subject: Fix UB in QFSFileEnginePrivate::writeFdFh() Apparently, it is considered valid to call the function with 'data' set to nullptr, and 'len' to zero. But doing so invokes undefined behavior because nullptr is passed to fwrite(). Fix by protecting the loops with 'if (len)'. Found by UBSan: qtbase/src/corelib/io/qfsfileengine.cpp:732:84: runtime error: null pointer passed as argument 1, which is declared to never be null Change-Id: Idfe23875c868ebb21d2164550de3304d2f01e9df Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/io/qfsfileengine.cpp | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 429c40da1a..10e116a23a 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -724,29 +724,33 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) qint64 writtenBytes = 0; - if (fh) { - // Buffered stdlib mode. - - size_t result; - do { - result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); - writtenBytes += result; - } while (result == 0 ? errno == EINTR : writtenBytes < len); + if (len) { // avoid passing nullptr to fwrite() or QT_WRITE() (UB) - } else if (fd != -1) { - // Unbuffered stdio mode. + if (fh) { + // Buffered stdlib mode. + + size_t result; + do { + result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); + writtenBytes += result; + } while (result == 0 ? errno == EINTR : writtenBytes < len); + + } else if (fd != -1) { + // Unbuffered stdio mode. + + SignedIOType result; + do { + // calculate the chunk size + // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks + // we limit to the size of the signed type, otherwise we could get a negative number as a result + quint64 wantedBytes = quint64(len) - quint64(writtenBytes); + UnsignedIOType chunkSize = std::numeric_limits::max(); + if (chunkSize > wantedBytes) + chunkSize = wantedBytes; + result = QT_WRITE(fd, data + writtenBytes, chunkSize); + } while (result > 0 && (writtenBytes += result) < len); + } - SignedIOType result; - do { - // calculate the chunk size - // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks - // we limit to the size of the signed type, otherwise we could get a negative number as a result - quint64 wantedBytes = quint64(len) - quint64(writtenBytes); - UnsignedIOType chunkSize = std::numeric_limits::max(); - if (chunkSize > wantedBytes) - chunkSize = wantedBytes; - result = QT_WRITE(fd, data + writtenBytes, chunkSize); - } while (result > 0 && (writtenBytes += result) < len); } if (len && writtenBytes == 0) { -- cgit v1.2.3 From 13189360e50a429ee43ce927c29ebcd3948619b7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 6 Jan 2016 13:31:11 +0100 Subject: Fix UB in QFileDevice::writeData() Passing nullptr as the 2nd argument of memcpy constitutes undefined behavior. Fix by protecting the block with 'if (len)', which, presumably, is the only valid case where 'data' may be nullptr. Change-Id: I7647d7e0808b1f26444ea3cf8bbf5cda9ddc9e6c Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/io/qfiledevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index 3ee0e33573..2d6be5fb80 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -560,7 +560,7 @@ qint64 QFileDevice::writeData(const char *data, qint64 len) char *writePointer = d->writeBuffer.reserve(len); if (len == 1) *writePointer = *data; - else + else if (len) ::memcpy(writePointer, data, len); return len; } -- cgit v1.2.3 From 61169b72c24b336af23702fda1e86d1d1c2c8095 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 6 Jan 2016 10:36:41 +0100 Subject: Fix UB in QIODevicePrivate Passing nullptr as the second argument of memcpy/memmove constitutes undefined behavior, even if the length argument is zero at the same time. Fix by protecting mem{cpy,move,chr} from nullptrs. Found by UBSan: qtbase/src/corelib/io/qiodevice_p.h:105:33: runtime error: null pointer passed as argument 2, which is declared to never be null qtbase/src/corelib/io/qiodevice_p.h:175:53: runtime error: null pointer passed as argument 2, which is declared to never be null Change-Id: I979158b0a74169ca4eb459928398ebc40f77dfb5 Reviewed-by: Alex Trotsenko Reviewed-by: Thiago Macieira --- src/corelib/io/qiodevice_p.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h index f4cf387eb5..8342176cff 100644 --- a/src/corelib/io/qiodevice_p.h +++ b/src/corelib/io/qiodevice_p.h @@ -102,14 +102,17 @@ public: } qint64 read(char* target, qint64 size) { qint64 r = qMin(size, len); - memcpy(target, first, r); - len -= r; - first += r; + if (r) { + memcpy(target, first, r); + len -= r; + first += r; + } return r; } qint64 peek(char* target, qint64 size) { qint64 r = qMin(size, len); - memcpy(target, first, r); + if (r) + memcpy(target, first, r); return r; } char* reserve(qint64 size) { @@ -141,7 +144,7 @@ public: return r; } bool canReadLine() const { - return memchr(first, '\n', len); + return first && memchr(first, '\n', len); } void ungetChar(char c) { if (first == buf) { @@ -172,7 +175,8 @@ private: if (newCapacity > capacity) { // allocate more space char* newBuf = new char[newCapacity]; - memmove(newBuf + moveOffset, first, len); + if (first) + memmove(newBuf + moveOffset, first, len); delete [] buf; buf = newBuf; capacity = newCapacity; -- cgit v1.2.3 From 5ef14c52d0275e721153b15acfb0410b9889014a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Wed, 13 Jan 2016 15:20:37 +0100 Subject: Fix QFileSelector::select if called with QUrl and scheme "assets" QFileSelector::select(QUrl) will use ":" for scheme "qrc" to call QFileSelector::select(QString). Scheme "assets" needs to remain "assets:" for select(QString), otherwise it won't recognize the file in "assets". Following failed because it was passed as ":/qml/example.qml" to select(QString): select(QUrl("assets:/qml/example.qml")); This will call select(QString) to: select("assets:/qml/example.qml"); Change-Id: I6bdeed6bb67992498ae3b8e1273c20e70049381a Task-number: QTBUG-50435 Reviewed-by: BogDan Vatra --- src/corelib/io/qfileselector.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 85d9b0bfcb..af8d9b2b36 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -248,9 +248,16 @@ QUrl QFileSelector::select(const QUrl &filePath) const return filePath; QUrl ret(filePath); if (isLocalScheme(filePath.scheme())) { - QString equivalentPath = QLatin1Char(':') + filePath.path(); + QLatin1String scheme(":"); +#ifdef Q_OS_ANDROID + // use other scheme because ":" means "qrc" here + if (filePath.scheme() == QLatin1String("assets")) + scheme = QLatin1String("assets:"); +#endif + + QString equivalentPath = scheme + filePath.path(); QString selectedPath = d->select(equivalentPath); - ret.setPath(selectedPath.remove(0, 1)); + ret.setPath(selectedPath.remove(0, scheme.size())); } else { ret = QUrl::fromLocalFile(d->select(ret.toLocalFile())); } -- cgit v1.2.3