1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qsharedmemory.h"
41 #include "qsharedmemory_p.h"
42 #include "qsystemsemaphore.h"
43 #include <qdir.h>
44 #include <qcryptographichash.h>
45 #include <qdebug.h>
46 #ifdef Q_OS_WIN
47 #  include <qt_windows.h>
48 #endif
49 
50 QT_BEGIN_NAMESPACE
51 
52 #if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE))
53 /*!
54     \internal
55 
56     Generate a string from the key which can be any unicode string into
57     the subset that the win/unix kernel allows.
58 
59     On Unix this will be a file name
60   */
61 QString
makePlatformSafeKey(const QString & key,const QString & prefix)62 QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
63                                           const QString &prefix)
64 {
65     if (key.isEmpty())
66         return QString();
67 
68     QString result = prefix;
69 
70     for (QChar ch : key) {
71         if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) ||
72            (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')))
73            result += ch;
74     }
75 
76     QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
77     result.append(QLatin1String(hex));
78 #ifdef Q_OS_WIN
79     return result;
80 #elif defined(QT_POSIX_IPC)
81     return QLatin1Char('/') + result;
82 #else
83     return QDir::tempPath() + QLatin1Char('/') + result;
84 #endif
85 }
86 #endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY
87 
88 #ifndef QT_NO_SHAREDMEMORY
89 
90 /*!
91   \class QSharedMemory
92   \inmodule QtCore
93   \since 4.4
94 
95   \brief The QSharedMemory class provides access to a shared memory segment.
96 
97   QSharedMemory provides access to a shared memory segment by multiple
98   threads and processes. It also provides a way for a single thread or
99   process to lock the memory for exclusive access.
100 
101   When using this class, be aware of the following platform
102   differences:
103 
104   \list
105 
106   \li Windows: QSharedMemory does not "own" the shared memory segment.
107   When all threads or processes that have an instance of QSharedMemory
108   attached to a particular shared memory segment have either destroyed
109   their instance of QSharedMemory or exited, the Windows kernel
110   releases the shared memory segment automatically.
111 
112   \li Unix: QSharedMemory "owns" the shared memory segment. When the
113   last thread or process that has an instance of QSharedMemory
114   attached to a particular shared memory segment detaches from the
115   segment by destroying its instance of QSharedMemory, the Unix kernel
116   release the shared memory segment. But if that last thread or
117   process crashes without running the QSharedMemory destructor, the
118   shared memory segment survives the crash.
119 
120   \li HP-UX: Only one attach to a shared memory segment is allowed per
121   process. This means that QSharedMemory should not be used across
122   multiple threads in the same process in HP-UX.
123 
124   \endlist
125 
126   Remember to lock the shared memory with lock() before reading from
127   or writing to the shared memory, and remember to release the lock
128   with unlock() after you are done.
129 
130   QSharedMemory automatically destroys the shared memory segment when
131   the last instance of QSharedMemory is detached from the segment, and
132   no references to the segment remain.
133 
134   \warning QSharedMemory changes the key in a Qt-specific way, unless otherwise
135   specified. Interoperation with non-Qt applications is achieved by first creating
136   a default shared memory with QSharedMemory() and then setting a native key with
137   setNativeKey(). When using native keys, shared memory is not protected against
138   multiple accesses on it (for example, unable to lock()) and a user-defined mechanism
139   should be used to achieve such protection.
140  */
141 
142 /*!
143   \overload QSharedMemory()
144 
145   Constructs a shared memory object with the given \a parent.  The
146   shared memory object's key is not set by the constructor, so the
147   shared memory object does not have an underlying shared memory
148   segment attached. The key must be set with setKey() or setNativeKey()
149   before create() or attach() can be used.
150 
151   \sa setKey()
152  */
153 
154 #ifndef QT_NO_QOBJECT
QSharedMemory(QObject * parent)155 QSharedMemory::QSharedMemory(QObject *parent)
156   : QObject(*new QSharedMemoryPrivate, parent)
157 {
158 }
159 #else
QSharedMemory()160 QSharedMemory::QSharedMemory()
161     : d_ptr(new QSharedMemoryPrivate)
162 {
163 }
164 #endif
165 /*!
166   Constructs a shared memory object with the given \a parent and with
167   its key set to \a key. Because its key is set, its create() and
168   attach() functions can be called.
169 
170   \sa setKey(), create(), attach()
171  */
172 #ifndef QT_NO_QOBJECT
QSharedMemory(const QString & key,QObject * parent)173 QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
174     : QObject(*new QSharedMemoryPrivate, parent)
175 {
176     setKey(key);
177 }
178 #else
QSharedMemory(const QString & key)179 QSharedMemory::QSharedMemory(const QString &key)
180     : d_ptr(new QSharedMemoryPrivate)
181 {
182     setKey(key);
183 }
184 #endif
185 
186 /*!
187   The destructor clears the key, which forces the shared memory object
188   to \l {detach()} {detach} from its underlying shared memory
189   segment. If this shared memory object is the last one connected to
190   the shared memory segment, the detach() operation destroys the
191   shared memory segment.
192 
193   \sa detach(), isAttached()
194  */
~QSharedMemory()195 QSharedMemory::~QSharedMemory()
196 {
197     setKey(QString());
198 }
199 
200 /*!
201   Sets the platform independent \a key for this shared memory object. If \a key
202   is the same as the current key, the function returns without doing anything.
203 
204   You can call key() to retrieve the platform independent key. Internally,
205   QSharedMemory converts this key into a platform specific key. If you instead
206   call nativeKey(), you will get the platform specific, converted key.
207 
208   If the shared memory object is attached to an underlying shared memory
209   segment, it will \l {detach()} {detach} from it before setting the new key.
210   This function does not do an attach().
211 
212   \sa key(), nativeKey(), isAttached()
213 */
setKey(const QString & key)214 void QSharedMemory::setKey(const QString &key)
215 {
216     Q_D(QSharedMemory);
217     if (key == d->key && d->makePlatformSafeKey(key) == d->nativeKey)
218         return;
219 
220     if (isAttached())
221         detach();
222     d->cleanHandle();
223     d->key = key;
224     d->nativeKey = d->makePlatformSafeKey(key);
225 }
226 
227 /*!
228   \since 4.8
229 
230   Sets the native, platform specific, \a key for this shared memory object. If
231   \a key is the same as the current native key, the function returns without
232   doing anything. If all you want is to assign a key to a segment, you should
233   call setKey() instead.
234 
235   You can call nativeKey() to retrieve the native key. If a native key has been
236   assigned, calling key() will return a null string.
237 
238   If the shared memory object is attached to an underlying shared memory
239   segment, it will \l {detach()} {detach} from it before setting the new key.
240   This function does not do an attach().
241 
242   The application will not be portable if you set a native key.
243 
244   \sa nativeKey(), key(), isAttached()
245 */
setNativeKey(const QString & key)246 void QSharedMemory::setNativeKey(const QString &key)
247 {
248     Q_D(QSharedMemory);
249     if (key == d->nativeKey && d->key.isNull())
250         return;
251 
252     if (isAttached())
253         detach();
254     d->cleanHandle();
255     d->key = QString();
256     d->nativeKey = key;
257 }
258 
initKey()259 bool QSharedMemoryPrivate::initKey()
260 {
261     if (!cleanHandle())
262         return false;
263 #ifndef QT_NO_SYSTEMSEMAPHORE
264     systemSemaphore.setKey(QString(), 1);
265     systemSemaphore.setKey(key, 1);
266     if (systemSemaphore.error() != QSystemSemaphore::NoError) {
267         QString function = QLatin1String("QSharedMemoryPrivate::initKey");
268         errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function);
269         switch(systemSemaphore.error()) {
270         case QSystemSemaphore::PermissionDenied:
271             error = QSharedMemory::PermissionDenied;
272             break;
273         case QSystemSemaphore::KeyError:
274             error = QSharedMemory::KeyError;
275             break;
276         case QSystemSemaphore::AlreadyExists:
277             error = QSharedMemory::AlreadyExists;
278             break;
279         case QSystemSemaphore::NotFound:
280             error = QSharedMemory::NotFound;
281             break;
282         case QSystemSemaphore::OutOfResources:
283             error = QSharedMemory::OutOfResources;
284             break;
285         case QSystemSemaphore::UnknownError:
286         default:
287             error = QSharedMemory::UnknownError;
288             break;
289         }
290         return false;
291     }
292 #endif
293     errorString = QString();
294     error = QSharedMemory::NoError;
295     return true;
296 }
297 
298 /*!
299   Returns the key assigned with setKey() to this shared memory, or a null key
300   if no key has been assigned, or if the segment is using a nativeKey(). The
301   key is the identifier used by Qt applications to identify the shared memory
302   segment.
303 
304   You can find the native, platform specific, key used by the operating system
305   by calling nativeKey().
306 
307   \sa setKey(), setNativeKey()
308  */
key() const309 QString QSharedMemory::key() const
310 {
311     Q_D(const QSharedMemory);
312     return d->key;
313 }
314 
315 /*!
316   \since 4.8
317 
318   Returns the native, platform specific, key for this shared memory object. The
319   native key is the identifier used by the operating system to identify the
320   shared memory segment.
321 
322   You can use the native key to access shared memory segments that have not
323   been created by Qt, or to grant shared memory access to non-Qt applications.
324 
325   \sa setKey(), setNativeKey()
326 */
nativeKey() const327 QString QSharedMemory::nativeKey() const
328 {
329     Q_D(const QSharedMemory);
330     return d->nativeKey;
331 }
332 
333 /*!
334   Creates a shared memory segment of \a size bytes with the key passed to the
335   constructor, set with setKey() or set with setNativeKey(), then attaches to
336   the new shared memory segment with the given access \a mode and returns
337   \tt true. If a shared memory segment identified by the key already exists,
338   the attach operation is not performed and \tt false is returned. When the
339   return value is \tt false, call error() to determine which error occurred.
340 
341   \sa error()
342  */
create(int size,AccessMode mode)343 bool QSharedMemory::create(int size, AccessMode mode)
344 {
345     Q_D(QSharedMemory);
346 
347     if (!d->initKey())
348         return false;
349 
350 #ifndef QT_NO_SYSTEMSEMAPHORE
351 #ifndef Q_OS_WIN
352     // Take ownership and force set initialValue because the semaphore
353     // might have already existed from a previous crash.
354     d->systemSemaphore.setKey(d->key, 1, QSystemSemaphore::Create);
355 #endif
356 #endif
357 
358     QString function = QLatin1String("QSharedMemory::create");
359 #ifndef QT_NO_SYSTEMSEMAPHORE
360     QSharedMemoryLocker lock(this);
361     if (!d->key.isNull() && !d->tryLocker(&lock, function))
362         return false;
363 #endif
364 
365     if (size <= 0) {
366         d->error = QSharedMemory::InvalidSize;
367         d->errorString =
368             QSharedMemory::tr("%1: create size is less then 0").arg(function);
369         return false;
370     }
371 
372     if (!d->create(size))
373         return false;
374 
375     return d->attach(mode);
376 }
377 
378 /*!
379   Returns the size of the attached shared memory segment. If no shared
380   memory segment is attached, 0 is returned.
381 
382   \note The size of the segment may be larger than the requested size that was
383   passed to create().
384 
385   \sa create(), attach()
386  */
size() const387 int QSharedMemory::size() const
388 {
389     Q_D(const QSharedMemory);
390     return d->size;
391 }
392 
393 /*!
394   \enum QSharedMemory::AccessMode
395 
396   \value ReadOnly The shared memory segment is read-only. Writing to
397   the shared memory segment is not allowed. An attempt to write to a
398   shared memory segment created with ReadOnly causes the program to
399   abort.
400 
401   \value ReadWrite Reading and writing the shared memory segment are
402   both allowed.
403 */
404 
405 /*!
406   Attempts to attach the process to the shared memory segment
407   identified by the key that was passed to the constructor or to a
408   call to setKey() or setNativeKey(). The access \a mode is \l {QSharedMemory::}
409   {ReadWrite} by default. It can also be \l {QSharedMemory::}
410   {ReadOnly}. Returns \c true if the attach operation is successful. If
411   false is returned, call error() to determine which error occurred.
412   After attaching the shared memory segment, a pointer to the shared
413   memory can be obtained by calling data().
414 
415   \sa isAttached(), detach(), create()
416  */
attach(AccessMode mode)417 bool QSharedMemory::attach(AccessMode mode)
418 {
419     Q_D(QSharedMemory);
420 
421     if (isAttached() || !d->initKey())
422         return false;
423 #ifndef QT_NO_SYSTEMSEMAPHORE
424     QSharedMemoryLocker lock(this);
425     if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::attach")))
426         return false;
427 #endif
428 
429     if (isAttached() || !d->handle())
430         return false;
431 
432     return d->attach(mode);
433 }
434 
435 /*!
436   Returns \c true if this process is attached to the shared memory
437   segment.
438 
439   \sa attach(), detach()
440  */
isAttached() const441 bool QSharedMemory::isAttached() const
442 {
443     Q_D(const QSharedMemory);
444     return (nullptr != d->memory);
445 }
446 
447 /*!
448   Detaches the process from the shared memory segment. If this was the
449   last process attached to the shared memory segment, then the shared
450   memory segment is released by the system, i.e., the contents are
451   destroyed. The function returns \c true if it detaches the shared
452   memory segment. If it returns \c false, it usually means the segment
453   either isn't attached, or it is locked by another process.
454 
455   \sa attach(), isAttached()
456  */
detach()457 bool QSharedMemory::detach()
458 {
459     Q_D(QSharedMemory);
460     if (!isAttached())
461         return false;
462 
463 #ifndef QT_NO_SYSTEMSEMAPHORE
464     QSharedMemoryLocker lock(this);
465     if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::detach")))
466         return false;
467 #endif
468 
469     return d->detach();
470 }
471 
472 /*!
473   Returns a pointer to the contents of the shared memory segment, if
474   one is attached. Otherwise it returns null. Remember to lock the
475   shared memory with lock() before reading from or writing to the
476   shared memory, and remember to release the lock with unlock() after
477   you are done.
478 
479   \sa attach()
480  */
data()481 void *QSharedMemory::data()
482 {
483     Q_D(QSharedMemory);
484     return d->memory;
485 }
486 
487 /*!
488   Returns a const pointer to the contents of the shared memory
489   segment, if one is attached. Otherwise it returns null. Remember to
490   lock the shared memory with lock() before reading from or writing to
491   the shared memory, and remember to release the lock with unlock()
492   after you are done.
493 
494   \sa attach(), create()
495  */
constData() const496 const void* QSharedMemory::constData() const
497 {
498     Q_D(const QSharedMemory);
499     return d->memory;
500 }
501 
502 /*!
503   \overload data()
504  */
data() const505 const void *QSharedMemory::data() const
506 {
507     Q_D(const QSharedMemory);
508     return d->memory;
509 }
510 
511 #ifndef QT_NO_SYSTEMSEMAPHORE
512 /*!
513   This is a semaphore that locks the shared memory segment for access
514   by this process and returns \c true. If another process has locked the
515   segment, this function blocks until the lock is released. Then it
516   acquires the lock and returns \c true. If this function returns \c false,
517   it means that you have ignored a false return from create() or attach(),
518   that you have set the key with setNativeKey() or that
519   QSystemSemaphore::acquire() failed due to an unknown system error.
520 
521   \sa unlock(), data(), QSystemSemaphore::acquire()
522  */
lock()523 bool QSharedMemory::lock()
524 {
525     Q_D(QSharedMemory);
526     if (d->lockedByMe) {
527         qWarning("QSharedMemory::lock: already locked");
528         return true;
529     }
530     if (d->systemSemaphore.acquire()) {
531         d->lockedByMe = true;
532         return true;
533     }
534     QString function = QLatin1String("QSharedMemory::lock");
535     d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function);
536     d->error = QSharedMemory::LockError;
537     return false;
538 }
539 
540 /*!
541   Releases the lock on the shared memory segment and returns \c true, if
542   the lock is currently held by this process. If the segment is not
543   locked, or if the lock is held by another process, nothing happens
544   and false is returned.
545 
546   \sa lock()
547  */
unlock()548 bool QSharedMemory::unlock()
549 {
550     Q_D(QSharedMemory);
551     if (!d->lockedByMe)
552         return false;
553     d->lockedByMe = false;
554     if (d->systemSemaphore.release())
555         return true;
556     QString function = QLatin1String("QSharedMemory::unlock");
557     d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function);
558     d->error = QSharedMemory::LockError;
559     return false;
560 }
561 #endif // QT_NO_SYSTEMSEMAPHORE
562 
563 /*!
564   \enum QSharedMemory::SharedMemoryError
565 
566   \value NoError No error occurred.
567 
568   \value PermissionDenied The operation failed because the caller
569   didn't have the required permissions.
570 
571   \value InvalidSize A create operation failed because the requested
572   size was invalid.
573 
574   \value KeyError The operation failed because of an invalid key.
575 
576   \value AlreadyExists A create() operation failed because a shared
577   memory segment with the specified key already existed.
578 
579   \value NotFound An attach() failed because a shared memory segment
580   with the specified key could not be found.
581 
582   \value LockError The attempt to lock() the shared memory segment
583   failed because create() or attach() failed and returned false, or
584   because a system error occurred in QSystemSemaphore::acquire().
585 
586   \value OutOfResources A create() operation failed because there was
587   not enough memory available to fill the request.
588 
589   \value UnknownError Something else happened and it was bad.
590 */
591 
592 /*!
593   Returns a value indicating whether an error occurred, and, if so,
594   which error it was.
595 
596   \sa errorString()
597  */
error() const598 QSharedMemory::SharedMemoryError QSharedMemory::error() const
599 {
600     Q_D(const QSharedMemory);
601     return d->error;
602 }
603 
604 /*!
605   Returns a text description of the last error that occurred. If
606   error() returns an \l {QSharedMemory::SharedMemoryError} {error
607   value}, call this function to get a text string that describes the
608   error.
609 
610   \sa error()
611  */
errorString() const612 QString QSharedMemory::errorString() const
613 {
614     Q_D(const QSharedMemory);
615     return d->errorString;
616 }
617 
618 #endif // QT_NO_SHAREDMEMORY
619 
620 QT_END_NAMESPACE
621 
622 #ifndef QT_NO_QOBJECT
623 #include "moc_qsharedmemory.cpp"
624 #endif
625