diff options
author | Mate Barany <mate.barany@qt.io> | 2023-01-13 18:18:08 +0100 |
---|---|---|
committer | Mate Barany <mate.barany@qt.io> | 2023-02-08 12:59:19 +0100 |
commit | 84f0596c0ca7cb5a31077cea29592781899c13f4 (patch) | |
tree | a4271a3d74a9fab51b0de3c692ebf323d13d28b3 /src/corelib | |
parent | 214c3a033a4e9191f0082bf6f88624d356a45384 (diff) |
Avoid potential data races caused by qt_ntfs_permission_lookup
qt_ntfs_permission_lookup is a global, non-atomic variable which
could cause problems in case of multiple threads. Introduce a
new atomic variable to handle permission lookups but instead of
manual incrementation/decrementation, implement a class to manage
the variable.
Since the atomic variable is not directly available to the user,
implement helper functions to increase/decrease/check the status
of the variable.
Task-number: QTBUG-105804
Change-Id: If6cbcdd653c7f50ad9853a5c309e24fdeb520788
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/doc/snippets/ntfsp.cpp | 15 | ||||
-rw-r--r-- | src/corelib/io/qfile.h | 21 | ||||
-rw-r--r-- | src/corelib/io/qfiledevice.cpp | 14 | ||||
-rw-r--r-- | src/corelib/io/qfileinfo.cpp | 13 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 45 |
5 files changed, 105 insertions, 3 deletions
diff --git a/src/corelib/doc/snippets/ntfsp.cpp b/src/corelib/doc/snippets/ntfsp.cpp index b4d59e6ac5..18f9bd0c5e 100644 --- a/src/corelib/doc/snippets/ntfsp.cpp +++ b/src/corelib/doc/snippets/ntfsp.cpp @@ -11,3 +11,18 @@ qt_ntfs_permission_lookup++; // turn checking on qt_ntfs_permission_lookup--; // turn it off again //! [1] +//! [raii] +void complexFunction() +{ + QNtfsPermissionCheckGuard permissionGuard; // check is enabled + + // do complex things here that need permission check enabled + +} // as the guard goes out of scope the check is disabled +//! [raii] + +//! [free-funcs] +qAreNtfsPermissionChecksEnabled(); // check status +qEnableNtfsPermissionChecks(); // turn checking on +qDisableNtfsPermissionChecks(); // turn it off again +//! [free-funcs] diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index 3ac6795495..f608ca48f5 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -26,6 +26,27 @@ namespace std { QT_BEGIN_NAMESPACE +#ifdef Q_OS_WIN +Q_CORE_EXPORT bool qEnableNtfsPermissionChecks() noexcept; +Q_CORE_EXPORT bool qDisableNtfsPermissionChecks() noexcept; +Q_CORE_EXPORT bool qAreNtfsPermissionChecksEnabled() noexcept; + +class [[nodiscard]] QNtfsPermissionCheckGuard +{ + Q_DISABLE_COPY_MOVE(QNtfsPermissionCheckGuard) +public: + QNtfsPermissionCheckGuard() + { + qEnableNtfsPermissionChecks(); + } + + ~QNtfsPermissionCheckGuard() + { + qDisableNtfsPermissionChecks(); + } +}; +#endif // Q_OS_WIN + #if QT_CONFIG(cxx17_filesystem) namespace QtPrivate { inline QString fromFilesystemPath(const std::filesystem::path &path) diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index 6c790e9d0e..092b09ae05 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -114,6 +114,20 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum) to increment or decrement \c qt_ntfs_permission_lookup before any threads other than the main thread have started or after every thread other than the main thread has ended. + + \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is + deprecated. Please use the following alternatives. + + The safe and easy way to manage permission checks is to use the RAII class + \c QNtfsPermissionCheckGuard. + + \snippet ntfsp.cpp raii + + If you need more fine-grained control, it is possible to manage the permission + with the following functions instead: + + \snippet ntfsp.cpp free-funcs + */ //************* QFileDevice diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 49573347ca..5c9ae5df70 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -278,6 +278,19 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) threads other than the main thread have started or after every thread other than the main thread has ended. + \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is + deprecated. Please use the following alternatives. + + The safe and easy way to manage permission checks is to use the RAII class + \c QNtfsPermissionCheckGuard. + + \snippet ntfsp.cpp raii + + If you need more fine-grained control, it is possible to manage the permission + with the following functions instead: + + \snippet ntfsp.cpp free-funcs + \section1 Performance Considerations Some of QFileInfo's functions query the file system, but for diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 9cfa1d7b7d..fbc55954cb 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -384,6 +384,46 @@ constexpr QFileDevice::Permissions toSpecificPermissions(PermissionTag tag, Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; +static QBasicAtomicInt qt_ntfs_permission_lookup_v2 = Q_BASIC_ATOMIC_INITIALIZER(0); + +/*! + \internal + + Returns true if the check was previously enabled. +*/ + +bool qEnableNtfsPermissionChecks() noexcept +{ + return qt_ntfs_permission_lookup_v2.fetchAndAddRelaxed(1) + + qt_ntfs_permission_lookup + != 0; +} + +/*! + \internal + + Returns true if the check is disabled, i.e. there are no more users. +*/ + +bool qDisableNtfsPermissionChecks() noexcept +{ + return qt_ntfs_permission_lookup_v2.fetchAndSubRelaxed(1) + + qt_ntfs_permission_lookup + == 1; +} + +/*! + \internal + + Returns true if the check is enabled. +*/ + +bool qAreNtfsPermissionChecksEnabled() noexcept +{ + return qt_ntfs_permission_lookup_v2.loadRelaxed() + + qt_ntfs_permission_lookup; +} + /*! \class QNativeFilePermissions \internal @@ -1078,8 +1118,7 @@ QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEng { QString name; #if QT_CONFIG(fslibs) - extern int qt_ntfs_permission_lookup; - if (qt_ntfs_permission_lookup > 0) { + if (qAreNtfsPermissionChecksEnabled()) { initGlobalSid(); { PSID pOwner = 0; @@ -1133,7 +1172,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst QFileSystemMetaData::MetaDataFlags what) { #if QT_CONFIG(fslibs) - if (qt_ntfs_permission_lookup > 0) { + if (qAreNtfsPermissionChecksEnabled()) { initGlobalSid(); QString fname = entry.nativeFilePath(); |