summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/configure.cmake4
-rw-r--r--src/corelib/kernel/qcore_mac.mm6
-rw-r--r--src/corelib/kernel/qcore_mac_p.h6
-rw-r--r--src/corelib/kernel/qsharedmemory.cpp63
-rw-r--r--src/corelib/kernel/qsharedmemory_posix.cpp2
-rw-r--r--src/corelib/kernel/qsystemsemaphore.cpp7
-rw-r--r--src/corelib/kernel/qsystemsemaphore_systemv.cpp14
-rw-r--r--src/corelib/kernel/qsystemsemaphore_unix.cpp6
-rw-r--r--tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp22
9 files changed, 113 insertions, 17 deletions
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index e82ac8bf93..b10c99246f 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -567,8 +567,8 @@ qt_feature("inotify" PUBLIC PRIVATE
qt_feature_definition("inotify" "QT_NO_INOTIFY" NEGATE VALUE "1")
qt_feature("ipc_posix"
LABEL "Using POSIX IPC"
- AUTODETECT NOT WIN32
- CONDITION NOT TEST_ipc_sysv AND TEST_ipc_posix
+ AUTODETECT NOT WIN32 AND ( ( APPLE AND QT_FEATURE_appstore_compliant ) OR NOT TEST_ipc_sysv )
+ CONDITION TEST_ipc_posix
)
qt_feature_definition("ipc_posix" "QT_POSIX_IPC")
qt_feature("journald" PRIVATE
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 6a8db38cc3..a4b8a4a628 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -396,9 +396,9 @@ AppleApplication *qt_apple_sharedApplication()
}
#endif
-#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
bool qt_apple_isSandboxed()
{
+#if defined(Q_OS_MACOS)
static bool isSandboxed = []() {
QCFType<SecStaticCodeRef> staticCode = nullptr;
NSURL *executableUrl = NSBundle.mainBundle.executableURL;
@@ -418,8 +418,12 @@ bool qt_apple_isSandboxed()
return true;
}();
return isSandboxed;
+#else
+ return true; // All other Apple platforms
+#endif
}
+#if !defined(QT_BOOTSTRAPPED)
QT_END_NAMESPACE
@implementation NSObject (QtSandboxHelpers)
- (id)qt_valueForPrivateKey:(NSString *)key
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 953e9ed6d7..7634ffb221 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -196,16 +196,14 @@ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
#endif
Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
-
-#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT bool qt_apple_isSandboxed();
-# ifdef __OBJC__
+
+#if !defined(QT_BOOTSTRAPPED) && defined(__OBJC__)
QT_END_NAMESPACE
@interface NSObject (QtSandboxHelpers)
- (id)qt_valueForPrivateKey:(NSString *)key;
@end
QT_BEGIN_NAMESPACE
-# endif
#endif
#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp
index 57f3d29077..3dbbe75fc4 100644
--- a/src/corelib/kernel/qsharedmemory.cpp
+++ b/src/corelib/kernel/qsharedmemory.cpp
@@ -47,6 +47,17 @@
# include <qt_windows.h>
#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
#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE))
@@ -65,16 +76,32 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
if (key.isEmpty())
return QString();
- QString result = prefix;
+ 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 <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;
+ } 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 QLatin1Char('/') + hex.left(SHM_NAME_MAX - 1);
+ }
+#endif
+
+ QString result = prefix;
for (QChar ch : key) {
if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) ||
(ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')))
result += ch;
}
-
- QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
result.append(QLatin1String(hex));
+
#ifdef Q_OS_WIN
return result;
#elif defined(QT_POSIX_IPC)
@@ -121,6 +148,36 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
process. This means that QSharedMemory should not be used across
multiple threads in the same process in HP-UX.
+ \li Apple platforms: Sandboxed applications (including apps
+ shipped through the Apple App Store) require the use of POSIX
+ shared memory (instead of System V shared memory), which adds
+ a number of limitations, including:
+
+ \list
+
+ \li The key must be in the form \c {<application group identifier>/<custom identifier>},
+ as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24}
+ {here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups}
+ {here}.
+
+ \li The key length is limited to 30 characters.
+
+ \li On process exit, the named shared memory entries are not
+ cleaned up, so restarting the application and re-creating the
+ shared memory under the same name will fail. To work around this,
+ fall back to attaching to the existing shared memory entry:
+
+ \code
+
+ QSharedMemory shm("DEVTEAMID.app-group/shared");
+ if (!shm.create(42) && shm.error() == QSharedMemory::AlreadyExists)
+ shm.attach();
+
+ \endcode
+
+
+ \endlist
+
\endlist
Remember to lock the shared memory with lock() before reading from
diff --git a/src/corelib/kernel/qsharedmemory_posix.cpp b/src/corelib/kernel/qsharedmemory_posix.cpp
index d83ff4cb92..9406e200be 100644
--- a/src/corelib/kernel/qsharedmemory_posix.cpp
+++ b/src/corelib/kernel/qsharedmemory_posix.cpp
@@ -102,7 +102,6 @@ bool QSharedMemoryPrivate::create(qsizetype size)
const int errorNumber = errno;
const QLatin1String function("QSharedMemory::attach (shm_open)");
switch (errorNumber) {
- case ENAMETOOLONG:
case EINVAL:
errorString = QSharedMemory::tr("%1: bad name").arg(function);
error = QSharedMemory::KeyError;
@@ -146,7 +145,6 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
const int errorNumber = errno;
const QLatin1String function("QSharedMemory::attach (shm_open)");
switch (errorNumber) {
- case ENAMETOOLONG:
case EINVAL:
errorString = QSharedMemory::tr("%1: bad name").arg(function);
error = QSharedMemory::KeyError;
diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp
index 011a673d69..063363189d 100644
--- a/src/corelib/kernel/qsystemsemaphore.cpp
+++ b/src/corelib/kernel/qsystemsemaphore.cpp
@@ -124,6 +124,13 @@ QT_BEGIN_NAMESPACE
\endlist
+ \b{Apple platforms:} Sandboxed applications (including apps
+ shipped through the Apple App Store) require the key to
+ be in the form \c {<application group identifier>/<custom identifier>},
+ as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24}
+ {here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups}
+ {here}, and the key length is limited to 30 characters.
+
\sa QSharedMemory, QSemaphore
*/
diff --git a/src/corelib/kernel/qsystemsemaphore_systemv.cpp b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
index d861a35358..1c9fc1f2f7 100644
--- a/src/corelib/kernel/qsystemsemaphore_systemv.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
@@ -54,6 +54,10 @@
#include <fcntl.h>
#include <errno.h>
+#if defined(Q_OS_DARWIN)
+#include "qcore_mac_p.h"
+#endif
+
#include "private/qcore_unix_p.h"
// OpenBSD 4.2 doesn't define EIDRM, see BUGS section:
@@ -71,6 +75,16 @@ QT_BEGIN_NAMESPACE
*/
key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
{
+#if defined(Q_OS_DARWIN)
+ if (qt_apple_isSandboxed()) {
+ errorString = QSystemSemaphore::tr("%1: System V semaphores are not available " \
+ "for sandboxed applications. Please build Qt with -feature-ipc_posix")
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
+ error = QSystemSemaphore::PermissionDenied;
+ return -1;
+ }
+#endif
+
if (key.isEmpty()){
errorString = QSystemSemaphore::tr("%1: key is empty")
.arg(QLatin1String("QSystemSemaphore::handle:"));
diff --git a/src/corelib/kernel/qsystemsemaphore_unix.cpp b/src/corelib/kernel/qsystemsemaphore_unix.cpp
index 25da6eb333..dad2249270 100644
--- a/src/corelib/kernel/qsystemsemaphore_unix.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_unix.cpp
@@ -89,6 +89,12 @@ void QSystemSemaphorePrivate::setErrorString(const QString &function)
errorString = QSystemSemaphore::tr("%1: out of resources").arg(function);
error = QSystemSemaphore::OutOfResources;
break;
+#if defined(QT_POSIX_IPC)
+ case ENAMETOOLONG:
+ errorString = QSystemSemaphore::tr("%1: key too long").arg(function);
+ error = QSystemSemaphore::KeyError;
+ break;
+#endif
default:
errorString = QSystemSemaphore::tr("%1: unknown error %2").arg(function).arg(errno);
error = QSystemSemaphore::UnknownError;
diff --git a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp
index 31b9c9740a..81a7dcf36f 100644
--- a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp
+++ b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp
@@ -182,14 +182,15 @@ int tst_QSharedMemory::remove(const QString &key)
if (key.isEmpty())
return -1;
- // ftok requires that an actual file exists somewhere
QString fileName = QSharedMemoryPrivate::makePlatformSafeKey(key);
+
+#ifndef QT_POSIX_IPC
+ // ftok requires that an actual file exists somewhere
if (!QFile::exists(fileName)) {
//qDebug() << "exits failed";
return -2;
}
-#ifndef QT_POSIX_IPC
int unix_key = ftok(fileName.toLatin1().constData(), 'Q');
if (-1 == unix_key) {
qDebug() << "ftok failed";
@@ -209,8 +210,10 @@ int tst_QSharedMemory::remove(const QString &key)
}
#else
if (shm_unlink(QFile::encodeName(fileName).constData()) == -1) {
- qDebug() << "shm_unlink failed";
- return -5;
+ if (errno != ENOENT) {
+ qDebug() << "shm_unlink failed";
+ return -5;
+ }
}
#endif // QT_POSIX_IPC
@@ -374,7 +377,7 @@ void tst_QSharedMemory::lock()
QVERIFY(!shm.lock());
QCOMPARE(shm.error(), QSharedMemory::LockError);
- shm.setKey(QLatin1String("qsharedmemory"));
+ shm.setKey(rememberKey(QLatin1String("qsharedmemory")));
QVERIFY(!shm.lock());
QCOMPARE(shm.error(), QSharedMemory::LockError);
@@ -411,6 +414,11 @@ void tst_QSharedMemory::removeWhileAttached()
delete smOne;
delete smTwo;
+#ifdef QT_POSIX_IPC
+ // POSIX IPC doesn't guarantee that the shared memory is removed
+ remove("one");
+#endif
+
// three shouldn't be able to attach
QSharedMemory smThree(QLatin1String("one"));
QVERIFY(!smThree.attach());
@@ -580,6 +588,10 @@ void tst_QSharedMemory::simpleDoubleProducerConsumer()
int size = 512;
QVERIFY(producer.create(size));
QVERIFY(producer.detach());
+#ifdef QT_POSIX_IPC
+ // POSIX IPC doesn't guarantee that the shared memory is removed
+ remove("market");
+#endif
QVERIFY(producer.create(size));
{