summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2017-02-27 14:03:15 +0100
committerOlivier Goffart (Woboq GmbH) <ogoffart@woboq.com>2017-03-10 17:09:24 +0000
commitb52b509ae48125ce9ba3cb50560e2e9ff81b485e (patch)
tree23af337d785f0abe19da0f30d844cfee29d02e77
parent137e6632c89a04c7785a005752e8a21b60678705 (diff)
QLockFile: Don't deadlock if the lock file has a mtime in the future
Stale Lock files in the future can happen in some situations. For exemple two computers with different clocks access the same file system. It could be that one of the timestamp is totaly off (several years into the future). [ChangeLog][QtCore][QLockFile] Fixed a deadlock occurring if a corrupted lock file's modification time is in the future. Change-Id: I8dac98a0e898c76bcef67f8c195e126c996b6add Reviewed-by: David Faure <david.faure@kdab.com>
-rw-r--r--src/corelib/io/qlockfile.cpp3
-rw-r--r--src/corelib/io/qlockfile_unix.cpp2
-rw-r--r--src/corelib/io/qlockfile_win.cpp2
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp28
4 files changed, 33 insertions, 2 deletions
diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp
index cb1ff93ad3..48317d07e0 100644
--- a/src/corelib/io/qlockfile.cpp
+++ b/src/corelib/io/qlockfile.cpp
@@ -44,6 +44,7 @@
#include <QtCore/qthread.h>
#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
QT_BEGIN_NAMESPACE
@@ -226,6 +227,8 @@ bool QLockFile::tryLock(int timeout)
return false;
case LockFailedError:
if (!d->isLocked && d->isApparentlyStale()) {
+ if (Q_UNLIKELY(QFileInfo(d->fileName).lastModified() > QDateTime::currentDateTime()))
+ qInfo("QLockFile: Lock file '%ls' has a modification time in the future", qUtf16Printable(d->fileName));
// Stale lock from another thread/process
// Ensure two processes don't remove it at the same time
QLockFile rmlock(d->fileName + QLatin1String(".rmlock"));
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 3a80014c00..5a02741727 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -247,7 +247,7 @@ bool QLockFilePrivate::isApparentlyStale() const
}
}
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
- return staleLockTime > 0 && age > staleLockTime;
+ return staleLockTime > 0 && qAbs(age) > staleLockTime;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index baaff8da17..4b43181686 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -160,7 +160,7 @@ bool QLockFilePrivate::isApparentlyStale() const
Q_UNUSED(appname);
#endif // Q_OS_WINRT
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
- return staleLockTime > 0 && age > staleLockTime;
+ return staleLockTime > 0 && qAbs(age) > staleLockTime;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
index a13ff0358a..d2f345feb5 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
@@ -34,6 +34,7 @@
#include <qsysinfo.h>
#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
#include <unistd.h>
+#include <sys/time.h>
#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
# include <qt_windows.h>
#endif
@@ -59,6 +60,7 @@ private slots:
void noPermissions();
void noPermissionsWindows();
void corruptedLockFile();
+ void corruptedLockFileInTheFuture();
private:
static bool overwritePidInLockFile(const QString &filePath, qint64 pid);
@@ -521,6 +523,32 @@ void tst_QLockFile::corruptedLockFile()
QCOMPARE(int(secondLock.error()), int(QLockFile::NoError));
}
+void tst_QLockFile::corruptedLockFileInTheFuture()
+{
+#if !defined(Q_OS_UNIX)
+ QSKIP("This tests needs utimes");
+#else
+ // This test is the same as the previous one, but the corruption was so there is a corrupted
+ // .rmlock whose timestamp is in the future
+
+ const QString fileName = dir.path() + "/corruptedLockFile.rmlock";
+
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::WriteOnly));
+ }
+
+ struct timeval times[2];
+ gettimeofday(times, 0);
+ times[1].tv_sec = (times[0].tv_sec += 600);
+ times[1].tv_usec = times[0].tv_usec;
+ utimes(fileName.toLocal8Bit(), times);
+
+ QTest::ignoreMessage(QtInfoMsg, "QLockFile: Lock file '" + fileName.toUtf8() + "' has a modification time in the future");
+ corruptedLockFile();
+#endif
+}
+
bool tst_QLockFile::overwritePidInLockFile(const QString &filePath, qint64 pid)
{
QFile f(filePath);