From 7809caa9244d3f6aedddcd9138e16be1806ded06 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 8 Oct 2022 00:25:17 -0700 Subject: [PATCH] IPC: move makePlatformSafeKey to qtipccommon.cpp This removes the second portion of the #if mess of shared code between QSharedMemory and QSystemSemaphore for SystemV. Change-Id: Id8d5e3999fe94b03acc1fffd171c073c2873206e Reviewed-by: Fabian Kosmale --- src/corelib/CMakeLists.txt | 1 + src/corelib/ipc/qsharedmemory.cpp | 74 ++------------- src/corelib/ipc/qsharedmemory_p.h | 19 +--- src/corelib/ipc/qsharedmemory_posix.cpp | 11 +-- src/corelib/ipc/qsystemsemaphore_p.h | 3 +- src/corelib/ipc/qtipccommon.cpp | 89 +++++++++++++++++++ src/corelib/ipc/qtipccommon_p.h | 7 ++ .../ipc/qsharedmemory/tst_qsharedmemory.cpp | 4 +- 8 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 src/corelib/ipc/qtipccommon.cpp diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index bd5306ede4..a2cb7f5308 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -110,6 +110,7 @@ qt_internal_add_module(Core global/qxptype_traits.h ipc/qsharedmemory.cpp ipc/qsharedmemory.h ipc/qsharedmemory_p.h ipc/qsystemsemaphore.cpp ipc/qsystemsemaphore.h ipc/qsystemsemaphore_p.h + ipc/qtipccommon.cpp ipc/qtipccommon_p.h io/qabstractfileengine.cpp io/qabstractfileengine_p.h io/qbuffer.cpp io/qbuffer.h io/qdataurl.cpp io/qdataurl_p.h diff --git a/src/corelib/ipc/qsharedmemory.cpp b/src/corelib/ipc/qsharedmemory.cpp index 2449564151..696dcb785b 100644 --- a/src/corelib/ipc/qsharedmemory.cpp +++ b/src/corelib/ipc/qsharedmemory.cpp @@ -3,81 +3,19 @@ #include "qsharedmemory.h" #include "qsharedmemory_p.h" + +#include "qtipccommon_p.h" #include "qsystemsemaphore.h" -#include -#include + #include #ifdef Q_OS_WIN # include #endif -#if defined(Q_OS_DARWIN) -# include "qcore_mac_p.h" -# if !defined(SHM_NAME_MAX) - // Based on PSEMNAMLEN in XNU's posix_sem.c, which would - // indicate the max length is 31, _excluding_ the zero - // terminator. But in practice (possibly due to an off- - // by-one bug in the kernel) the usable bytes are only 30. -# define SHM_NAME_MAX 30 -# endif -#endif - QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore) -/*! - \internal - - Generate a string from the key which can be any unicode string into - the subset that the win/unix kernel allows. - - On Unix this will be a file name - */ -QString -QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, - const QString &prefix) -{ - if (key.isEmpty()) - return QString(); - - QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); - -#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC) - if (qt_apple_isSandboxed()) { - // Sandboxed applications on Apple platforms require the shared memory name - // to be in the form /. - // Since we don't know which application group identifier the user wants - // to apply, we instead document that requirement, and use the key directly. - return key; - } else { - // The shared memory name limit on Apple platforms is very low (30 characters), - // so we can't use the logic below of combining the prefix, key, and a hash, - // to ensure a unique and valid name. Instead we use the first part of the - // hash, which should still long enough to avoid collisions in practice. - return u'/' + hex.left(SHM_NAME_MAX - 1); - } -#endif - - QString result = prefix; - for (QChar ch : key) { - if ((ch >= u'a' && ch <= u'z') || - (ch >= u'A' && ch <= u'Z')) - result += ch; - } - result.append(QLatin1StringView(hex)); - -#ifdef Q_OS_WIN - return result; -#elif defined(QT_POSIX_IPC) - return u'/' + result; -#else - return QDir::tempPath() + u'/' + result; -#endif -} -#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore) - #if QT_CONFIG(sharedmemory) /*! @@ -306,14 +244,16 @@ QSharedMemory::~QSharedMemory() void QSharedMemory::setKey(const QString &key) { Q_D(QSharedMemory); - if (key == d->key && d->makePlatformSafeKey(key) == d->nativeKey) + QString newNativeKey = + QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory); + if (key == d->key && newNativeKey == d->nativeKey) return; if (isAttached()) detach(); d->cleanHandle(); d->key = key; - d->nativeKey = d->makePlatformSafeKey(key); + d->nativeKey = newNativeKey; } /*! diff --git a/src/corelib/ipc/qsharedmemory_p.h b/src/corelib/ipc/qsharedmemory_p.h index 3a7a95e4d0..039b54eb69 100644 --- a/src/corelib/ipc/qsharedmemory_p.h +++ b/src/corelib/ipc/qsharedmemory_p.h @@ -19,22 +19,7 @@ #include -#if !QT_CONFIG(sharedmemory) -# if QT_CONFIG(systemsemaphore) - -QT_BEGIN_NAMESPACE - -namespace QSharedMemoryPrivate -{ - QString makePlatformSafeKey(const QString &key, - const QString &prefix = QStringLiteral("qipc_sharedmemory_")); -} - -QT_END_NAMESPACE - -# endif -#else - +#if QT_CONFIG(sharedmemory) #include "qsystemsemaphore.h" #include "private/qobject_p.h" @@ -92,8 +77,6 @@ public: bool lockedByMe = false; #endif - static QString makePlatformSafeKey(const QString &key, - const QString &prefix = QStringLiteral("qipc_sharedmemory_")); #ifdef Q_OS_WIN Qt::HANDLE handle(); #elif defined(QT_POSIX_IPC) diff --git a/src/corelib/ipc/qsharedmemory_posix.cpp b/src/corelib/ipc/qsharedmemory_posix.cpp index ac316b9d12..05ed377e62 100644 --- a/src/corelib/ipc/qsharedmemory_posix.cpp +++ b/src/corelib/ipc/qsharedmemory_posix.cpp @@ -7,7 +7,7 @@ #include "qsharedmemory.h" #include "qsharedmemory_p.h" -#include "qsystemsemaphore.h" +#include "qtipccommon_p.h" #include #include @@ -26,11 +26,12 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +using namespace QtIpcCommon; int QSharedMemoryPrivate::handle() { // don't allow making handles on empty keys - const QString safeKey = makePlatformSafeKey(key); + const QString safeKey = legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory); if (safeKey.isEmpty()) { errorString = QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1); error = QSharedMemory::KeyError; @@ -53,7 +54,7 @@ bool QSharedMemoryPrivate::create(qsizetype size) if (!handle()) return false; - const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory)); int fd; #ifdef O_CLOEXEC @@ -94,7 +95,7 @@ bool QSharedMemoryPrivate::create(qsizetype size) bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { - const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory)); const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR); const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600); @@ -180,7 +181,7 @@ bool QSharedMemoryPrivate::detach() // if there are no attachments then unlink the shared memory if (shm_nattch == 0) { - const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory)); if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT) setErrorString("QSharedMemory::detach (shm_unlink)"_L1); } diff --git a/src/corelib/ipc/qsystemsemaphore_p.h b/src/corelib/ipc/qsystemsemaphore_p.h index 6a4cb73982..1efc9d4e1c 100644 --- a/src/corelib/ipc/qsystemsemaphore_p.h +++ b/src/corelib/ipc/qsystemsemaphore_p.h @@ -21,7 +21,6 @@ #include "qcoreapplication.h" #include "qtipccommon_p.h" -#include "qsharedmemory_p.h" #include #ifdef QT_POSIX_IPC @@ -37,7 +36,7 @@ public: QString makeKeyFileName() { - return QSharedMemoryPrivate::makePlatformSafeKey(key, QLatin1StringView("qipc_systemsem_")); + return QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SystemSemaphore); } inline void setError(QSystemSemaphore::SystemSemaphoreError e, const QString &message) diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp new file mode 100644 index 0000000000..461f5b09c2 --- /dev/null +++ b/src/corelib/ipc/qtipccommon.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2022 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qtipccommon_p.h" + +#include +#include + +#if defined(Q_OS_DARWIN) +# include "private/qcore_mac_p.h" +# if !defined(SHM_NAME_MAX) + // Based on PSEMNAMLEN in XNU's posix_sem.c, which would + // indicate the max length is 31, _excluding_ the zero + // terminator. But in practice (possibly due to an off- + // by-one bug in the kernel) the usable bytes are only 30. +# define SHM_NAME_MAX 30 +# endif +#endif + +#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore) + +QT_BEGIN_NAMESPACE + +using namespace Qt::StringLiterals; + +/*! + \internal + + Legacy: this exists for compatibility with QSharedMemory and + QSystemSemaphore between 4.4 and 6.6. + + Generate a string from the key which can be any unicode string into + the subset that the win/unix kernel allows. + + On Unix this will be a file name +*/ +QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType) +{ + if (key.isEmpty()) + return QString(); + + QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); + +#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC) + if (qt_apple_isSandboxed()) { + // Sandboxed applications on Apple platforms require the shared memory name + // to be in the form /. + // Since we don't know which application group identifier the user wants + // to apply, we instead document that requirement, and use the key directly. + return key; + } else { + // The shared memory name limit on Apple platforms is very low (30 characters), + // so we can't use the logic below of combining the prefix, key, and a hash, + // to ensure a unique and valid name. Instead we use the first part of the + // hash, which should still long enough to avoid collisions in practice. + return u'/' + hex.left(SHM_NAME_MAX - 1); + } +#endif + + QString result; + result.reserve(1 + 18 + key.size() + 40); + switch (ipcType) { + case IpcType::SharedMemory: + result += "qipc_sharedmemory_"_L1; + break; + case IpcType::SystemSemaphore: + result += "qipc_systemsem_"_L1; + break; + } + + for (QChar ch : key) { + if ((ch >= u'a' && ch <= u'z') || + (ch >= u'A' && ch <= u'Z')) + result += ch; + } + result.append(QLatin1StringView(hex)); + +#ifdef Q_OS_WIN + return result; +#elif defined(QT_POSIX_IPC) + return u'/' + result; +#else + return QDir::tempPath() + u'/' + result; +#endif +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore) diff --git a/src/corelib/ipc/qtipccommon_p.h b/src/corelib/ipc/qtipccommon_p.h index bb8dacaed1..223916897a 100644 --- a/src/corelib/ipc/qtipccommon_p.h +++ b/src/corelib/ipc/qtipccommon_p.h @@ -27,6 +27,13 @@ QT_BEGIN_NAMESPACE namespace QtIpcCommon { +enum class IpcType { + SharedMemory, + SystemSemaphore +}; + +Q_AUTOTEST_EXPORT QString legacyPlatformSafeKey(const QString &key, IpcType ipcType); + #ifdef Q_OS_UNIX // Convenience function to create the file if needed inline int createUnixKeyFile(const QByteArray &fileName) diff --git a/tests/auto/corelib/ipc/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/corelib/ipc/qsharedmemory/tst_qsharedmemory.cpp index 2bf8a74a1e..3dde642152 100644 --- a/tests/auto/corelib/ipc/qsharedmemory/tst_qsharedmemory.cpp +++ b/tests/auto/corelib/ipc/qsharedmemory/tst_qsharedmemory.cpp @@ -135,7 +135,7 @@ void tst_QSharedMemory::cleanup() } #ifndef Q_OS_WIN -#include +#include #include #ifndef QT_POSIX_IPC #include @@ -157,7 +157,7 @@ int tst_QSharedMemory::remove(const QString &key) if (key.isEmpty()) return -1; - QString fileName = QSharedMemoryPrivate::makePlatformSafeKey(key); + QString fileName = QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory); #ifndef QT_POSIX_IPC // ftok requires that an actual file exists somewhere