QDBusServer: Fix potential crash when private pointer is null

Check that the private pointer is not null before attempting
to dereference it. This can happen, for example, when
a QDBusServer instance was constructed with an empty string
as address. Attempting to destroy an object constructed
this way was causing a segmentation fault on Linux.

Add a test case that attempts to construct a QDBusServer
object with an empty string as address to check that this
does not cause a segmentation fault anymore.

Change-Id: I5fe63134026e2a9f509b61d452285891b1ec624d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 90d3c5b95145c1fa326d1d6d9fa5bcd7b3dedc4c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ievgenii Meshcheriakov 2023-04-27 16:29:01 +02:00 committed by Qt Cherry-pick Bot
parent 8a35934362
commit a558ecb235
3 changed files with 30 additions and 10 deletions

View File

@ -39,6 +39,8 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent)
return; return;
emit instance->serverRequested(address, this); emit instance->serverRequested(address, this);
Q_ASSERT(d != nullptr);
QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)), QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection); this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
} }
@ -66,6 +68,8 @@ QDBusServer::QDBusServer(QObject *parent)
return; return;
emit instance->serverRequested(address, this); emit instance->serverRequested(address, this);
Q_ASSERT(d != nullptr);
QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)), QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection); this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
} }
@ -75,17 +79,20 @@ QDBusServer::QDBusServer(QObject *parent)
*/ */
QDBusServer::~QDBusServer() QDBusServer::~QDBusServer()
{ {
QMutex *managerMutex = nullptr; if (!d)
if (QDBusConnectionManager::instance()) return;
managerMutex = &QDBusConnectionManager::instance()->mutex;
QMutexLocker locker(managerMutex); auto manager = QDBusConnectionManager::instance();
if (!manager)
return;
QMutexLocker locker(&manager->mutex);
QWriteLocker writeLocker(&d->lock); QWriteLocker writeLocker(&d->lock);
if (QDBusConnectionManager::instance()) { for (const QString &name : std::as_const(d->serverConnectionNames))
for (const QString &name : std::as_const(d->serverConnectionNames)) manager->removeConnection(name);
QDBusConnectionManager::instance()->removeConnection(name); d->serverConnectionNames.clear();
d->serverConnectionNames.clear(); locker.unlock();
locker.unlock();
}
d->serverObject = nullptr; d->serverObject = nullptr;
d->ref.storeRelaxed(0); d->ref.storeRelaxed(0);
d->deleteLater(); d->deleteLater();
@ -138,6 +145,9 @@ QString QDBusServer::address() const
*/ */
void QDBusServer::setAnonymousAuthenticationAllowed(bool value) void QDBusServer::setAnonymousAuthenticationAllowed(bool value)
{ {
if (!d)
return;
d->anonymousAuthenticationAllowed = value; d->anonymousAuthenticationAllowed = value;
} }
@ -150,6 +160,9 @@ void QDBusServer::setAnonymousAuthenticationAllowed(bool value)
*/ */
bool QDBusServer::isAnonymousAuthenticationAllowed() const bool QDBusServer::isAnonymousAuthenticationAllowed() const
{ {
if (!d)
return false;
return d->anonymousAuthenticationAllowed; return d->anonymousAuthenticationAllowed;
} }

View File

@ -1412,6 +1412,11 @@ void tst_QDBusConnection::pendingCallWhenDisconnected()
#endif #endif
} }
void tst_QDBusConnection::emptyServerAddress()
{
QDBusServer server({}, nullptr);
}
QString MyObject::path; QString MyObject::path;
QString MyObjectWithoutInterface::path; QString MyObjectWithoutInterface::path;
QString MyObjectWithoutInterface::interface; QString MyObjectWithoutInterface::interface;

View File

@ -115,6 +115,8 @@ private slots:
void callVirtualObjectLocal(); void callVirtualObjectLocal();
void pendingCallWhenDisconnected(); void pendingCallWhenDisconnected();
void emptyServerAddress();
public: public:
QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; } QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; }
bool callMethod(const QDBusConnection &conn, const QString &path); bool callMethod(const QDBusConnection &conn, const QString &path);