Coverage Report

Created: 2026-08-17 07:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/dbus/qdbusinterface.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#include "qdbusinterface.h"
6
#include "qdbusinterface_p.h"
7
8
#include "qdbus_symbols_p.h"
9
#include <QtCore/qpointer.h>
10
#include <QtCore/qstringlist.h>
11
12
#include "qdbusmetatype_p.h"
13
#include "qdbusconnection_p.h"
14
15
#ifndef QT_NO_DBUS
16
17
QT_BEGIN_NAMESPACE
18
19
using namespace Qt::StringLiterals;
20
21
static void copyArgument(void *to, int id, const QVariant &arg)
22
0
{
23
0
    if (id == arg.metaType().id()) {
24
0
        switch (id) {
25
0
        case QMetaType::Bool:
26
0
            *reinterpret_cast<bool *>(to) = arg.toBool();
27
0
            return;
28
29
0
        case QMetaType::UChar:
30
0
            *reinterpret_cast<uchar *>(to) = qvariant_cast<uchar>(arg);
31
0
            return;
32
33
0
        case QMetaType::Short:
34
0
            *reinterpret_cast<short *>(to) = qvariant_cast<short>(arg);
35
0
            return;
36
37
0
        case QMetaType::UShort:
38
0
            *reinterpret_cast<ushort *>(to) = qvariant_cast<ushort>(arg);
39
0
            return;
40
41
0
        case QMetaType::Int:
42
0
            *reinterpret_cast<int *>(to) = arg.toInt();
43
0
            return;
44
45
0
        case QMetaType::UInt:
46
0
            *reinterpret_cast<uint *>(to) = arg.toUInt();
47
0
            return;
48
49
0
        case QMetaType::LongLong:
50
0
            *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
51
0
            return;
52
53
0
        case QMetaType::ULongLong:
54
0
            *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
55
0
            return;
56
57
0
        case QMetaType::Double:
58
0
            *reinterpret_cast<double *>(to) = arg.toDouble();
59
0
            return;
60
61
0
        case QMetaType::QString:
62
0
            *reinterpret_cast<QString *>(to) = arg.toString();
63
0
            return;
64
65
0
        case QMetaType::QByteArray:
66
0
            *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
67
0
            return;
68
69
0
        case QMetaType::QStringList:
70
0
            *reinterpret_cast<QStringList *>(to) = arg.toStringList();
71
0
            return;
72
0
        }
73
74
0
        if (id == QDBusMetaTypeId::variant().id()) {
75
0
            *reinterpret_cast<QDBusVariant *>(to) = qvariant_cast<QDBusVariant>(arg);
76
0
            return;
77
0
        } else if (id == QDBusMetaTypeId::objectpath().id()) {
78
0
            *reinterpret_cast<QDBusObjectPath *>(to) = qvariant_cast<QDBusObjectPath>(arg);
79
0
            return;
80
0
        } else if (id == QDBusMetaTypeId::signature().id()) {
81
0
            *reinterpret_cast<QDBusSignature *>(to) = qvariant_cast<QDBusSignature>(arg);
82
0
            return;
83
0
        }
84
85
        // those above are the only types possible
86
        // the demarshaller code doesn't demarshall anything else
87
0
        qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
88
0
    }
89
90
    // if we got here, it's either an un-dermarshalled type or a mismatch
91
0
    if (arg.metaType() != QDBusMetaTypeId::argument()) {
92
        // it's a mismatch
93
        //qWarning?
94
0
        return;
95
0
    }
96
97
    // is this type registered?
98
0
    const char *userSignature = QDBusMetaType::typeToSignature(QMetaType(id));
99
0
    if (!userSignature || !*userSignature) {
100
        // type not registered
101
        //qWarning?
102
0
        return;
103
0
    }
104
105
    // is it the same signature?
106
0
    QDBusArgument dbarg = qvariant_cast<QDBusArgument>(arg);
107
0
    if (dbarg.currentSignature() != QLatin1StringView(userSignature)) {
108
        // not the same signature, another mismatch
109
        //qWarning?
110
0
        return;
111
0
    }
112
113
    // we can demarshall
114
0
    QDBusMetaType::demarshall(dbarg, QMetaType(id), to);
115
0
}
116
117
QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
118
                                             const QString &iface, const QDBusConnection &con)
119
0
    : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(nullptr)
120
0
{
121
    // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
122
0
    if (connection.isConnected()) {
123
0
        metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
124
125
0
        if (!metaObject) {
126
            // creation failed, somehow
127
            // most common causes are that the service doesn't exist or doesn't support introspection
128
            // those are not fatal errors, so we continue working
129
130
0
            if (!lastError.isValid())
131
0
                lastError = QDBusError(QDBusError::InternalError, "Unknown error"_L1);
132
0
        }
133
0
    }
134
0
}
135
136
QDBusInterfacePrivate::~QDBusInterfacePrivate()
137
0
{
138
0
    if (metaObject && !metaObject->cached)
139
0
        delete metaObject;
140
0
}
141
142
143
/*!
144
    \class QDBusInterface
145
    \inmodule QtDBus
146
    \since 4.2
147
148
    \brief The QDBusInterface class is a proxy for interfaces on remote objects.
149
150
    QDBusInterface is a generic accessor class that is used to place calls to remote objects,
151
    connect to signals exported by remote objects and get/set the value of remote properties. This
152
    class is useful for dynamic access to remote objects: that is, when you do not have a generated
153
    code that represents the remote interface.
154
155
    Calls are usually placed by using the call() function, which constructs the message, sends it
156
    over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
157
    normal QObject::connect() function. Finally, properties are accessed using the
158
    QObject::property() and QObject::setProperty() functions.
159
160
    The following code snippet demonstrates how to perform a
161
    mathematical operation of \tt{"2 + 2"} in a remote application
162
    called \c com.example.Calculator, accessed via the session bus.
163
164
    \snippet code/src_qdbus_qdbusinterface.cpp 0
165
166
    \sa {Qt D-Bus XML compiler (qdbusxml2cpp)}
167
*/
168
169
/*!
170
    Creates a dynamic QDBusInterface object associated with the
171
    interface \a interface on object at path \a path on service \a
172
    service, using the given \a connection. If \a interface is an
173
    empty string, the object created will refer to the merging of all
174
    interfaces found by introspecting that object. Otherwise if
175
    \a interface is not empty, the  QDBusInterface object will be cached
176
    to speedup further creations of the same interface.
177
178
    \a parent is passed to the base class constructor.
179
180
    If the remote service \a service is not present or if an error
181
    occurs trying to obtain the description of the remote interface
182
    \a interface, the object created will not be valid (see
183
    isValid()).
184
*/
185
QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
186
                               const QDBusConnection &connection, QObject *parent)
187
0
    : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
188
0
                             parent)
189
0
{
190
0
}
191
192
/*!
193
    Destroy the object interface and frees up any resource used.
194
*/
195
QDBusInterface::~QDBusInterface()
196
0
{
197
    // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
198
0
}
199
200
/*!
201
    \internal
202
    Overrides QObject::metaObject to return our own copy.
203
*/
204
const QMetaObject *QDBusInterface::metaObject() const
205
0
{
206
0
    return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
207
0
}
208
209
/*!
210
    \internal
211
    Override QObject::qt_metacast to catch the interface name too.
212
*/
213
void *QDBusInterface::qt_metacast(const char *_clname)
214
0
{
215
0
    if (!_clname) return nullptr;
216
0
    if (!strcmp(_clname, "QDBusInterface"))
217
0
        return static_cast<void*>(const_cast<QDBusInterface*>(this));
218
0
    if (d_func()->interface.toLatin1() == _clname)
219
0
        return static_cast<void*>(const_cast<QDBusInterface*>(this));
220
0
    return QDBusAbstractInterface::qt_metacast(_clname);
221
0
}
222
223
/*!
224
    \internal
225
    Dispatch the call through the private.
226
*/
227
int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
228
0
{
229
0
    _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
230
0
    if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
231
0
        return _id;
232
0
    return d_func()->metacall(_c, _id, _a);
233
0
}
234
235
int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
236
0
{
237
0
    Q_Q(QDBusInterface);
238
239
0
    if (c == QMetaObject::InvokeMetaMethod) {
240
0
        int offset = metaObject->methodOffset();
241
0
        QMetaMethod mm = metaObject->method(id + offset);
242
243
0
        if (mm.methodType() == QMetaMethod::Signal) {
244
            // signal relay from D-Bus world to Qt world
245
0
            QMetaObject::activate(q, metaObject, id, argv);
246
247
0
        } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
248
            // method call relay from Qt world to D-Bus world
249
            // get D-Bus equivalent signature
250
0
            QString methodName = QString::fromLatin1(mm.name());
251
0
            const int *inputTypes = metaObject->inputTypesForMethod(id);
252
0
            int inputTypesCount = *inputTypes;
253
254
            // we will assume that the input arguments were passed correctly
255
0
            QVariantList args;
256
0
            args.reserve(inputTypesCount);
257
0
            int i = 1;
258
0
            for ( ; i <= inputTypesCount; ++i)
259
0
                args << QVariant(QMetaType(inputTypes[i]), argv[i]);
260
261
            // make the call
262
0
            QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
263
264
0
            if (reply.type() == QDBusMessage::ReplyMessage) {
265
                // attempt to demarshall the return values
266
0
                args = reply.arguments();
267
0
                QVariantList::ConstIterator it = args.constBegin();
268
0
                const int *outputTypes = metaObject->outputTypesForMethod(id);
269
0
                int outputTypesCount = *outputTypes++;
270
271
0
                if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) {
272
                    // this method has a return type
273
0
                    if (argv[0] && it != args.constEnd())
274
0
                        copyArgument(argv[0], *outputTypes++, *it);
275
276
                    // skip this argument even if we didn't copy it
277
0
                    --outputTypesCount;
278
0
                    ++it;
279
0
                }
280
281
0
                for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
282
0
                    copyArgument(argv[i], outputTypes[j], *it);
283
0
                }
284
0
            }
285
286
            // done
287
0
            lastError = QDBusError(reply);
288
0
            return -1;
289
0
        }
290
0
    }
291
0
    return id;
292
0
}
293
294
QT_END_NAMESPACE
295
296
#endif // QT_NO_DBUS