Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsharedpointer.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2020 Intel Corporation.
3// Copyright (C) 2019 Klarälvdalens Datakonsult AB.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qsharedpointer.h"
7
8// to be sure we aren't causing a namespace clash:
9#include "qshareddata.h"
10
1415#include <qset.h>
1416#include <qmutex.h>
1417
1418#if !defined(QT_NO_QOBJECT)
1419#include "private/qobject_p.h"
1420
1422
1430{}
1431)
1432
1433QT6_ONLY(
1441void QtSharedPointer::ExternalRefCountData::checkQObjectShared(const QObject *)
1442{
1443 if (strongref.loadRelaxed() < 0)
1444 qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
1445}
1446)
1447
1449{
1450 Q_ASSERT(obj);
1451 QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
1452 Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted");
1453
1454 ExternalRefCountData *that = d->sharedRefcount.loadRelaxed();
1455 if (that) {
1456 that->weakref.ref();
1457 return that;
1458 }
1459
1460 // we can create the refcount data because it doesn't exist
1462 x->strongref.storeRelaxed(-1);
1463 x->weakref.storeRelaxed(2); // the QWeakPointer that called us plus the QObject itself
1464
1466 if (d->sharedRefcount.testAndSetOrdered(nullptr, x, ret)) { // ought to be release+acquire; this is acq_rel+acquire
1467 ret = x;
1468 } else {
1469 // ~ExternalRefCountData has a Q_ASSERT, so we use this trick to
1470 // only execute this if Q_ASSERTs are enabled
1471 Q_ASSERT((x->weakref.storeRelaxed(0), true));
1472 ::delete x;
1473 ret->weakref.ref();
1474 }
1475 return ret;
1476}
1477
1484{
1486 return *reinterpret_cast<const QSharedPointer<QObject>*>(variant.constData());
1487}
1488
1495{
1498 return *reinterpret_cast<const QWeakPointer<QObject>*>(variant.constData());
1499}
1500
1502
1503#endif
1504
1505
1506
1507//# define QT_SHARED_POINTER_BACKTRACE_SUPPORT
1508# ifdef QT_SHARED_POINTER_BACKTRACE_SUPPORT
1509# if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__) && !defined(QT_LINUXBASE)
1510# define BACKTRACE_SUPPORTED
1511# elif defined(Q_OS_DARWIN)
1512# define BACKTRACE_SUPPORTED
1513# endif
1514# endif
1515
1516# if defined(BACKTRACE_SUPPORTED)
1517# include <sys/types.h>
1518# include <execinfo.h>
1519# include <stdio.h>
1520# include <unistd.h>
1521# include <sys/wait.h>
1522
1524
1525static inline QByteArray saveBacktrace() __attribute__((always_inline));
1526static inline QByteArray saveBacktrace()
1527{
1528 static const int maxFrames = 32;
1529
1530 QByteArray stacktrace;
1531 stacktrace.resize(sizeof(void*) * maxFrames);
1532 int stack_size = backtrace((void**)stacktrace.data(), maxFrames);
1533 stacktrace.resize(sizeof(void*) * stack_size);
1534
1535 return stacktrace;
1536}
1537
1538static void printBacktrace(QByteArray stacktrace)
1539{
1540 void *const *stack = (void *const *)stacktrace.constData();
1541 int stack_size = stacktrace.size() / sizeof(void*);
1542 char **stack_symbols = backtrace_symbols(stack, stack_size);
1543
1544 int filter[2];
1545 pid_t child = -1;
1546 if (pipe(filter) != -1)
1547 child = fork();
1548 if (child == 0) {
1549 // child process
1550 dup2(fileno(stderr), fileno(stdout));
1551 dup2(filter[0], fileno(stdin));
1552 close(filter[0]);
1553 close(filter[1]);
1554 execlp("c++filt", "c++filt", "-n", NULL);
1555
1556 // execlp failed
1557 execl("/bin/cat", "/bin/cat", NULL);
1558 _exit(127);
1559 }
1560
1561 // parent process
1562 close(filter[0]);
1563 FILE *output;
1564 if (child == -1) {
1565 // failed forking
1566 close(filter[1]);
1567 output = stderr;
1568 } else {
1569 output = fdopen(filter[1], "w");
1570 }
1571
1572 fprintf(stderr, "Backtrace of the first creation (most recent frame first):\n");
1573 for (int i = 0; i < stack_size; ++i) {
1574 if (strlen(stack_symbols[i]))
1575 fprintf(output, "#%-2d %s\n", i, stack_symbols[i]);
1576 else
1577 fprintf(output, "#%-2d %p\n", i, stack[i]);
1578 }
1579
1580 if (child != -1) {
1581 fclose(output);
1582 waitpid(child, 0, 0);
1583 }
1584}
1585
1587
1588# endif // BACKTRACE_SUPPORTED
1589
1590namespace {
1592 struct Data {
1593 const volatile void *pointer;
1594# ifdef BACKTRACE_SUPPORTED
1595 QByteArray backtrace;
1596# endif
1597 };
1598
1600 {
1601 public:
1603 QHash<const void *, Data> dPointers;
1604 QHash<const volatile void *, const void *> dataPointers;
1605 };
1606}
1607
1608Q_GLOBAL_STATIC(KnownPointers, knownPointers)
1609
1611
1612namespace QtSharedPointer {
1614}
1615
1619void QtSharedPointer::internalSafetyCheckAdd(const void *d_ptr, const volatile void *ptr)
1620{
1621 KnownPointers *const kp = knownPointers();
1622 if (!kp)
1623 return; // end-game: the application is being destroyed already
1624
1625 if (!ptr) {
1626 // nullptr is allowed to be tracked by more than one QSharedPointer, so we
1627 // need something else to put in our tracking structures
1628 ptr = d_ptr;
1629 }
1630
1631 QMutexLocker lock(&kp->mutex);
1632 Q_ASSERT(!kp->dPointers.contains(d_ptr));
1633
1634 //qDebug("Adding d=%p value=%p", d_ptr, ptr);
1635
1636 const void *other_d_ptr = kp->dataPointers.value(ptr, nullptr);
1637 if (Q_UNLIKELY(other_d_ptr)) {
1638# ifdef BACKTRACE_SUPPORTED
1639 printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace);
1640# endif
1641 qFatal("QSharedPointer: internal self-check failed: pointer %p was already tracked "
1642 "by another QSharedPointer object %p", ptr, other_d_ptr);
1643 }
1644
1645 Data data;
1646 data.pointer = ptr;
1647# ifdef BACKTRACE_SUPPORTED
1648 data.backtrace = saveBacktrace();
1649# endif
1650
1651 kp->dPointers.insert(d_ptr, data);
1652 kp->dataPointers.insert(ptr, d_ptr);
1653 Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
1654}
1655
1660{
1661 KnownPointers *const kp = knownPointers();
1662 if (!kp)
1663 return; // end-game: the application is being destroyed already
1664
1665 QMutexLocker lock(&kp->mutex);
1666
1667 const auto it = kp->dPointers.constFind(d_ptr);
1668 if (Q_UNLIKELY(it == kp->dPointers.cend())) {
1669 qFatal("QSharedPointer: internal self-check inconsistency: pointer %p was not tracked. "
1670 "To use QT_SHAREDPOINTER_TRACK_POINTERS, you have to enable it throughout "
1671 "in your code.", d_ptr);
1672 }
1673
1674 const auto it2 = kp->dataPointers.constFind(it->pointer);
1675 Q_ASSERT(it2 != kp->dataPointers.cend());
1676
1677 //qDebug("Removing d=%p value=%p", d_ptr, it->pointer);
1678
1679 // remove entries
1680 kp->dataPointers.erase(it2);
1681 kp->dPointers.erase(it);
1682 Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
1683}
1684
1690{
1691# ifdef QT_BUILD_INTERNAL
1692 KnownPointers *const kp = knownPointers();
1693 Q_ASSERT_X(kp, "internalSafetyCheckSelfCheck()", "Called after global statics deletion!");
1694
1695 if (Q_UNLIKELY(kp->dPointers.size() != kp->dataPointers.size()))
1696 qFatal("Internal consistency error: the number of pointers is not equal!");
1697
1698 if (Q_UNLIKELY(!kp->dPointers.isEmpty()))
1699 qFatal("Pointer cleaning failed: %d entries remaining", int(kp->dPointers.size()));
1700# endif
1701}
1702
bool ref() noexcept
\inmodule QtCore
Definition qbytearray.h:57
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
@ SharedPointerToQObject
Definition qmetatype.h:408
@ WeakPointerToQObject
Definition qmetatype.h:409
@ TrackingPointerToQObject
Definition qmetatype.h:410
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
value_type * pointer
Definition qset.h:170
const_iterator cend() const noexcept
Definition qset.h:142
const_iterator constFind(const T &value) const
Definition qset.h:161
QHash< const void *, Data > dPointers
QHash< const volatile void *, const void * > dataPointers
\inmodule QtCore
Definition qvariant.h:65
QMetaType metaType() const
const void * constData() const
Definition qvariant.h:451
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Q_CORE_EXPORT QWeakPointer< QObject > weakPointerFromVariant_internal(const QVariant &variant)
Q_AUTOTEST_EXPORT void internalSafetyCheckCleanCheck()
Q_CORE_EXPORT void internalSafetyCheckRemove(const void *)
Q_CORE_EXPORT void internalSafetyCheckAdd(const void *, const volatile void *)
Q_CORE_EXPORT QSharedPointer< QObject > sharedPointerFromVariant_internal(const QVariant &variant)
constexpr Initialization Uninitialized
#define Q_UNLIKELY(x)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
return ret
static ControlElement< T > * ptr(QWidget *widget)
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLhandleARB obj
[2]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QT_BEGIN_NAMESPACE QT6_ONLY(void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *, bool) {}) QT6_ONLY(void QtSharedPointer
#define Q_AUTOTEST_EXPORT
QT_BEGIN_NAMESPACE typedef uchar * output
QVariant variant
[1]
QReadWriteLock lock
[0]
QLayoutItem * child
[0]
const volatile void * pointer
static Q_CORE_EXPORT ExternalRefCountData * getAndRef(const QObject *)