summaryrefslogtreecommitdiffstats
path: root/src/corelib/ipc/qtipccommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/ipc/qtipccommon.cpp')
-rw-r--r--src/corelib/ipc/qtipccommon.cpp246
1 files changed, 151 insertions, 95 deletions
diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp
index 46a4777104..b2ae9172fa 100644
--- a/src/corelib/ipc/qtipccommon.cpp
+++ b/src/corelib/ipc/qtipccommon.cpp
@@ -7,7 +7,8 @@
#include <qcryptographichash.h>
#include <qstandardpaths.h>
#include <qstringconverter.h>
-#include <private/qurl_p.h>
+#include <qurl.h>
+#include <qurlquery.h>
#if defined(Q_OS_DARWIN)
# include "private/qcore_mac_p.h"
@@ -18,6 +19,8 @@
// by-one bug in the kernel) the usable bytes are only 30.
# define SHM_NAME_MAX 30
# endif
+#elif defined(Q_OS_WINDOWS)
+# include "qt_windows.h"
#endif
#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
@@ -91,16 +94,18 @@ static QNativeIpcKey::Type stringToType(QStringView typeString)
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
+ Returns a QNativeIpcKey that contains a platform-safe key using rules
+ similar to QtIpcCommon::platformSafeKey() below, but using an algorithm
+ that is compatible with Qt 4.4 to 6.6. Additionally, the returned
+ QNativeIpcKey will record the input \a key so it can be included in the
+ string form if necessary to pass to other processes.
*/
-QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+QNativeIpcKey QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return QString();
+ return k;
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
@@ -111,13 +116,16 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
// to be in the form <application group identifier>/<custom identifier>.
// 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;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, key, 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.
+ QString native = u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, native, key);
}
- // 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'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ return k;
#endif
}
@@ -141,38 +149,51 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
switch (type) {
case QNativeIpcKey::Type::Windows:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
- return QString();
- return result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
- return result.prepend(u'/');
+ result.prepend(u'/');
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ result = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ }
+ return k;
}
-QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+/*!
+ \internal
+ Returns a QNativeIpcKey of type \a type, suitable for QSystemSemaphore or
+ QSharedMemory depending on \a ipcType. The returned native key is generated
+ from the Unicode input \a key and is safe for use on for the key type in
+ question in the current OS.
+*/
+QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return key;
+ return k;
switch (type) {
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) {
#ifdef SHM_NAME_MAX
- // The shared memory name limit on Apple platforms is very low (30
- // characters), so we have to cut it down to avoid ENAMETOOLONG. We
- // hope that there won't be too many collisions...
- return u'/' + QStringView(key).left(SHM_NAME_MAX - 1);
+ // The shared memory name limit on Apple platforms is very low (30
+ // characters), so we have to cut it down to avoid ENAMETOOLONG. We
+ // hope that there won't be too many collisions...
+ k.setNativeKey(u'/' + QStringView(key).left(SHM_NAME_MAX - 1));
+#else
+ k.setNativeKey(u'/' + key);
#endif
- return u'/' + key;
+ }
+ return k;
case QNativeIpcKey::Type::Windows:
if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) {
@@ -194,25 +215,27 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
}
QString result = prefix + mid + payload;
-#ifdef MAX_PATH
+#ifdef Q_OS_WINDOWS
result.truncate(MAX_PATH);
#endif
- return result;
+ k.setNativeKey(result);
}
- return QString();
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
// System V
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- if (key.startsWith(u'/'))
- return key;
-
- QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- return baseDir + u'/' + key;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ if (key.startsWith(u'/')) {
+ k.setNativeKey(key);
+ } else {
+ QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+ k.setNativeKey(baseDir + u'/' + key);
+ }
+ }
+ return k;
}
/*!
@@ -221,6 +244,8 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
\since 6.6
\brief The QNativeIpcKey class holds a native key used by QSystemSemaphore and QSharedMemory.
+ \compares equality
+
The \l QSharedMemory and \l QSystemSemaphore classes identify their
resource using a system-wide identifier known as a "key". The low-level key
value as well as the key type are encapsulated in Qt using the \l
@@ -343,6 +368,11 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
}
#endif
+/*!
+ \fn QNativeIpcKey::QNativeIpcKey() noexcept
+
+ Constructs a QNativeIpcKey object of type \l DefaultTypeForOs with an empty key.
+*/
/*!
\fn QNativeIpcKey::QNativeIpcKey(Type type) noexcept
@@ -360,19 +390,26 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
Copies or moves the content of \a other.
*/
-void QNativeIpcKey::copy_internal(const QNativeIpcKey &)
+void QNativeIpcKey::copy_internal(const QNativeIpcKey &other)
{
- Q_UNREACHABLE();
+ d = new QNativeIpcKeyPrivate(*other.d);
}
void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
{
- Q_UNREACHABLE();
+ // inline code already moved properly, nothing for us to do here
}
-QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &)
+QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
{
- Q_UNREACHABLE_RETURN(*this);
+ Q_ASSERT(d || other.d); // only 3 cases to handle
+ if (d && !other.d)
+ *d = {};
+ else if (d)
+ *d = *other.d;
+ else
+ d = new QNativeIpcKeyPrivate(*other.d);
+ return *this;
}
/*!
@@ -382,16 +419,22 @@ QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &)
*/
void QNativeIpcKey::destroy_internal() noexcept
{
- Q_ASSERT(isSlowPath());
- Q_UNREACHABLE();
+ delete d;
}
/*!
\fn QNativeIpcKey::swap(QNativeIpcKey &other) noexcept
- \fn swap(QNativeIpcKey &lhs, QNativeIpcKey &rhs) noexcept
- Swaps the native IPC key and type \a other with this object, or \a lhs with
- \a rhs. This operation is very fast and never fails.
+ Swaps the native IPC key and type \a other with this object.
+ This operation is very fast and never fails.
+*/
+
+/*!
+ \fn swap(QNativeIpcKey &value1, QNativeIpcKey &value2) noexcept
+ \relates QNativeIpcKey
+
+ Swaps the native IPC key and type \a value1 with \a value2.
+ This operation is very fast and never fails.
*/
/*!
@@ -422,11 +465,6 @@ void QNativeIpcKey::destroy_internal() noexcept
\sa nativeKey(), setType()
*/
-QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
-{
- Q_ASSERT(isSlowPath());
- Q_UNREACHABLE_RETURN({});
-}
/*!
\fn QNativeIpcKey::setType(Type type)
@@ -435,9 +473,9 @@ QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
\sa type(), setNativeKey()
*/
-void QNativeIpcKey::setType_internal(Type)
+void QNativeIpcKey::setType_internal(Type type)
{
- Q_UNREACHABLE();
+ Q_UNUSED(type);
}
/*!
@@ -455,6 +493,28 @@ void QNativeIpcKey::setType_internal(Type)
\sa nativeKey(), setType()
*/
+void QNativeIpcKey::setNativeKey_internal(const QString &)
+{
+ d->legacyKey_.clear();
+}
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey) noexcept
+
+ Returns the hash value for \a ipcKey, using a default seed of \c 0.
+*/
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+
+ Returns the hash value for \a ipcKey, using \a seed to seed the calculation.
+*/
+size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+{
+ // by *choice*, we're not including d->legacyKey_ in the hash -- it's
+ // already partially encoded in the key
+ return qHashMulti(seed, ipcKey.key, ipcKey.type());
+}
/*!
\fn bool QNativeIpcKey::operator==(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
@@ -462,9 +522,9 @@ void QNativeIpcKey::setType_internal(Type)
Returns true if the \a lhs and \a rhs objects hold the same (or different) contents.
*/
-int QNativeIpcKey::compare_internal(const QNativeIpcKey &, const QNativeIpcKey &) noexcept
+int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
{
- Q_UNREACHABLE_RETURN(0);
+ return (QNativeIpcKeyPrivate::legacyKey(lhs) == QNativeIpcKeyPrivate::legacyKey(rhs)) ? 0 : 1;
}
/*!
@@ -479,28 +539,27 @@ int QNativeIpcKey::compare_internal(const QNativeIpcKey &, const QNativeIpcKey &
*/
QString QNativeIpcKey::toString() const
{
- Q_ASSERT(!isSlowPath());
- QString prefix = typeToString(typeAndFlags.type);
+ QString prefix = typeToString(type());
if (prefix.isEmpty()) {
Q_ASSERT(prefix.isNull());
return prefix;
}
- prefix += u':';
QString copy = nativeKey();
copy.replace(u'%', "%25"_L1);
if (copy.startsWith("//"_L1))
copy.replace(0, 2, u"/%2F"_s); // ensure it's parsed as a URL path
- const ushort recodeActions[] = {
- '\\' | 0, // decode
- '?' | 0x200, // encode
- '#' | 0x200, // encode
- 0
- };
- if (!qt_urlRecode(prefix, copy, QUrl::DecodeReserved, recodeActions))
- prefix += copy;
- return prefix;
+ QUrl u;
+ u.setScheme(prefix);
+ u.setPath(copy, QUrl::TolerantMode);
+ if (isSlowPath()) {
+ QUrlQuery q;
+ if (!d->legacyKey_.isEmpty())
+ q.addQueryItem(u"legacyKey"_s, QString(d->legacyKey_).replace(u'%', "%25"_L1));
+ u.setQuery(q);
+ }
+ return u.toString(QUrl::DecodeReserved);
}
/*!
@@ -515,14 +574,11 @@ QString QNativeIpcKey::toString() const
*/
QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
{
- // this duplicates QUrlPrivate::parse a little
+ QUrl u(text, QUrl::TolerantMode);
Type invalidType = {};
- qsizetype colon = text.indexOf(u':');
- if (colon < 0)
- return QNativeIpcKey(invalidType);
-
- Type type = stringToType(QStringView(text).left(colon));
- if (type == invalidType)
+ Type type = stringToType(u.scheme());
+ if (type == invalidType || !u.isValid() || !u.userInfo().isEmpty() || !u.host().isEmpty()
+ || u.port() != -1)
return QNativeIpcKey(invalidType);
QNativeIpcKey result(QString(), type);
@@ -530,20 +586,20 @@ QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
return QNativeIpcKey(invalidType);
// decode the payload
- QStringView payload = QStringView(text).sliced(colon + 1);
- if (qsizetype pos = payload.indexOf(u'?'); pos >= 0)
- payload.truncate(pos);
- if (qsizetype pos = payload.indexOf(u'#'); pos >= 0)
- payload.truncate(pos);
-
- // qt_urlRecode requires a two-step decoding for non-ASCII content
- QString nativeKey, intermediate;
- if (qt_urlRecode(intermediate, payload, QUrl::PrettyDecoded))
- payload = intermediate;
- if (!qt_urlRecode(nativeKey, payload, QUrl::FullyDecoded))
- nativeKey = payload.toString();
-
- result.setNativeKey(nativeKey);
+ result.setNativeKey(u.path());
+
+ if (u.hasQuery()) {
+ const QList items = QUrlQuery(u).queryItems();
+ for (const auto &item : items) {
+ if (item.first == u"legacyKey"_s) {
+ QString legacyKey = QUrl::fromPercentEncoding(item.second.toUtf8());
+ QNativeIpcKeyPrivate::setLegacyKey(result, std::move(legacyKey));
+ } else {
+ // unknown query item
+ return QNativeIpcKey(invalidType);
+ }
+ }
+ }
return result;
}