Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/dbus/qdbusmarshaller.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:critical reason:data-parser
4
5
#include "qdbusargument_p.h"
6
#include "qdbusconnection.h"
7
#include "qdbusmetatype_p.h"
8
#include "qdbusutil_p.h"
9
10
#ifndef QT_NO_DBUS
11
12
QT_BEGIN_NAMESPACE
13
14
using namespace Qt::StringLiterals;
15
16
static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
17
0
{
18
0
    if (ba)
19
0
        *ba += char(type);
20
0
    else
21
0
        q_dbus_message_iter_append_basic(it, type, arg);
22
0
}
23
24
QDBusMarshaller::~QDBusMarshaller()
25
0
{
26
0
    close();
27
0
}
28
29
void QDBusMarshaller::unregisteredTypeError(QMetaType id)
30
0
{
31
0
    const char *name = id.name();
32
0
    qWarning("QDBusMarshaller: type '%s' (%d) is not registered with D-Bus. "
33
0
             "Use qDBusRegisterMetaType to register it",
34
0
             name ? name : "", id.id());
35
0
    error("Unregistered type %1 passed in arguments"_L1
36
0
          .arg(QLatin1StringView(id.name())));
37
0
}
38
39
inline QString QDBusMarshaller::currentSignature()
40
0
{
41
0
    if (message)
42
0
        return QString::fromUtf8(q_dbus_message_get_signature(message));
43
0
    return QString();
44
0
}
45
46
inline void QDBusMarshaller::append(uchar arg)
47
0
{
48
0
    if (!skipSignature)
49
0
        qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
50
0
}
51
52
inline void QDBusMarshaller::append(bool arg)
53
0
{
54
0
    dbus_bool_t cast = arg;
55
0
    if (!skipSignature)
56
0
        qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
57
0
}
58
59
inline void QDBusMarshaller::append(short arg)
60
0
{
61
0
    if (!skipSignature)
62
0
        qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
63
0
}
64
65
inline void QDBusMarshaller::append(ushort arg)
66
0
{
67
0
    if (!skipSignature)
68
0
        qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
69
0
}
70
71
inline void QDBusMarshaller::append(int arg)
72
0
{
73
0
    if (!skipSignature)
74
0
        qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
75
0
}
76
77
inline void QDBusMarshaller::append(uint arg)
78
0
{
79
0
    if (!skipSignature)
80
0
        qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
81
0
}
82
83
inline void QDBusMarshaller::append(qlonglong arg)
84
0
{
85
0
    if (!skipSignature)
86
0
        qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
87
0
}
88
89
inline void QDBusMarshaller::append(qulonglong arg)
90
0
{
91
0
    if (!skipSignature)
92
0
        qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
93
0
}
94
95
inline void QDBusMarshaller::append(double arg)
96
0
{
97
0
    if (!skipSignature)
98
0
        qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
99
0
}
100
101
void QDBusMarshaller::append(const QString &arg)
102
0
{
103
0
    QByteArray data = arg.toUtf8();
104
0
    const char *cdata = data.constData();
105
0
    if (!skipSignature)
106
0
        qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
107
0
}
108
109
inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
110
0
{
111
0
    QByteArray data = arg.path().toUtf8();
112
0
    if (!ba && data.isEmpty()) {
113
0
        error("Invalid object path passed in arguments"_L1);
114
0
    } else {
115
0
        const char *cdata = data.constData();
116
0
        if (!skipSignature)
117
0
            qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
118
0
    }
119
0
}
120
121
inline void QDBusMarshaller::append(const QDBusSignature &arg)
122
0
{
123
0
    QByteArray data = arg.signature().toUtf8();
124
0
    if (!ba && data.isNull()) {
125
0
        error("Invalid signature passed in arguments"_L1);
126
0
    } else {
127
0
        const char *cdata = data.constData();
128
0
        if (!skipSignature)
129
0
            qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
130
0
    }
131
0
}
132
133
inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg)
134
0
{
135
0
    int fd = arg.fileDescriptor();
136
0
    if (!ba && fd == -1) {
137
0
        error("Invalid file descriptor passed in arguments"_L1);
138
0
    } else {
139
0
        if (!skipSignature)
140
0
            qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd);
141
0
    }
142
0
}
143
144
inline void QDBusMarshaller::append(const QByteArray &arg)
145
0
{
146
0
    if (ba) {
147
0
        if (!skipSignature)
148
0
            *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
149
0
        return;
150
0
    }
151
152
0
    const char* cdata = arg.constData();
153
0
    DBusMessageIter subiterator;
154
0
    q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
155
0
                                     &subiterator);
156
0
    q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.size());
157
0
    q_dbus_message_iter_close_container(&iterator, &subiterator);
158
0
}
159
160
inline bool QDBusMarshaller::append(const QDBusVariant &arg)
161
0
{
162
0
    if (ba) {
163
0
        if (!skipSignature)
164
0
            *ba += DBUS_TYPE_VARIANT_AS_STRING;
165
0
        return true;
166
0
    }
167
168
0
    const QVariant &value = arg.variant();
169
0
    QMetaType id = value.metaType();
170
0
    if (!id.isValid()) {
171
0
        qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
172
0
        error("Invalid QVariant passed in arguments"_L1);
173
0
        return false;
174
0
    }
175
176
0
    QByteArray tmpSignature;
177
0
    const char *signature = nullptr;
178
0
    if (id == QDBusMetaTypeId::argument()) {
179
        // take the signature from the QDBusArgument object we're marshalling
180
0
        tmpSignature =
181
0
            qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
182
0
        signature = tmpSignature.constData();
183
0
    } else {
184
        // take the signatuer from the metatype we're marshalling
185
0
        signature = QDBusMetaType::typeToSignature(id);
186
0
    }
187
0
    if (!signature) {
188
0
        unregisteredTypeError(id);
189
0
        return false;
190
0
    }
191
192
0
    QDBusMarshaller sub(capabilities);
193
0
    open(sub, DBUS_TYPE_VARIANT, signature);
194
0
    bool isOk = sub.appendVariantInternal(value);
195
    // don't call sub.close(): it auto-closes
196
197
0
    return isOk;
198
0
}
199
200
inline void QDBusMarshaller::append(const QStringList &arg)
201
0
{
202
0
    if (ba) {
203
0
        if (!skipSignature)
204
0
            *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
205
0
        return;
206
0
    }
207
208
0
    QDBusMarshaller sub(capabilities);
209
0
    open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
210
0
    for (const QString &s : arg)
211
0
        sub.append(s);
212
    // don't call sub.close(): it auto-closes
213
0
}
214
215
inline QDBusMarshaller *QDBusMarshaller::beginStructure()
216
0
{
217
0
    return beginCommon(DBUS_TYPE_STRUCT, nullptr);
218
0
}
219
220
inline QDBusMarshaller *QDBusMarshaller::beginArray(QMetaType id)
221
0
{
222
0
    const char *signature = QDBusMetaType::typeToSignature(id);
223
0
    if (!signature) {
224
0
        unregisteredTypeError(id);
225
0
        return this;
226
0
    }
227
228
0
    return beginCommon(DBUS_TYPE_ARRAY, signature);
229
0
}
230
231
inline QDBusMarshaller *QDBusMarshaller::beginMap(QMetaType kid, QMetaType vid)
232
0
{
233
0
    const char *ksignature = QDBusMetaType::typeToSignature(kid);
234
0
    if (!ksignature) {
235
0
        unregisteredTypeError(kid);
236
0
        return this;
237
0
    }
238
0
    if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
239
0
QT_WARNING_PUSH
240
0
QT_WARNING_DISABLE_GCC("-Wformat-overflow")
241
0
        qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-Bus map.",
242
0
                 kid.name(), kid.id());
243
0
QT_WARNING_POP
244
0
        error("Type %1 passed in arguments cannot be used as a key in a map"_L1
245
0
              .arg(QLatin1StringView(kid.name())));
246
0
        return this;
247
0
    }
248
249
0
    const char *vsignature = QDBusMetaType::typeToSignature(vid);
250
0
    if (!vsignature) {
251
0
        unregisteredTypeError(vid);
252
0
        return this;
253
0
    }
254
255
0
    QByteArray signature;
256
0
    signature = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
257
0
    signature += ksignature;
258
0
    signature += vsignature;
259
0
    signature += DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
260
0
    return beginCommon(DBUS_TYPE_ARRAY, signature);
261
0
}
262
263
inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
264
0
{
265
0
    return beginCommon(DBUS_TYPE_DICT_ENTRY, nullptr);
266
0
}
267
268
void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
269
0
{
270
0
    sub.parent = this;
271
0
    sub.ba = ba;
272
0
    sub.ok = true;
273
0
    sub.capabilities = capabilities;
274
0
    sub.skipSignature = skipSignature;
275
276
0
    if (ba) {
277
0
        if (!skipSignature) {
278
0
            switch (code) {
279
0
            case DBUS_TYPE_ARRAY:
280
0
                *ba += char(code);
281
0
                *ba += signature;
282
0
                Q_FALLTHROUGH();
283
284
0
            case DBUS_TYPE_DICT_ENTRY:
285
0
                sub.closeCode = 0;
286
0
                sub.skipSignature = true;
287
0
                break;
288
289
0
            case DBUS_TYPE_STRUCT:
290
0
                *ba += DBUS_STRUCT_BEGIN_CHAR;
291
0
                sub.closeCode = DBUS_STRUCT_END_CHAR;
292
0
                break;
293
0
            }
294
0
        }
295
0
    } else {
296
0
        q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
297
0
    }
298
0
}
299
300
QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
301
0
{
302
0
    QDBusMarshaller *d = new QDBusMarshaller(capabilities);
303
0
    open(*d, code, signature);
304
0
    return d;
305
0
}
306
307
inline QDBusMarshaller *QDBusMarshaller::endStructure()
308
0
{ return endCommon(); }
309
310
inline QDBusMarshaller *QDBusMarshaller::endArray()
311
0
{ return endCommon(); }
312
313
inline QDBusMarshaller *QDBusMarshaller::endMap()
314
0
{ return endCommon(); }
315
316
inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
317
0
{ return endCommon(); }
318
319
QDBusMarshaller *QDBusMarshaller::endCommon()
320
0
{
321
0
    QDBusMarshaller *retval = parent;
322
0
    delete this;
323
0
    return retval;
324
0
}
325
326
void QDBusMarshaller::close()
327
0
{
328
0
    if (ba) {
329
0
        if (!skipSignature && closeCode)
330
0
            *ba += closeCode;
331
0
    } else if (parent) {
332
0
        q_dbus_message_iter_close_container(&parent->iterator, &iterator);
333
0
    }
334
0
}
335
336
void QDBusMarshaller::error(const QString &msg)
337
0
{
338
0
    ok = false;
339
0
    if (parent)
340
0
        parent->error(msg);
341
0
    else
342
0
        errorString = msg;
343
0
}
344
345
bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
346
0
{
347
0
    QMetaType id = arg.metaType();
348
0
    if (!id.isValid()) {
349
0
        qWarning("QDBusMarshaller: cannot add an invalid QVariant");
350
0
        error("Invalid QVariant passed in arguments"_L1);
351
0
        return false;
352
0
    }
353
354
    // intercept QDBusArgument parameters here
355
0
    if (id == QDBusMetaTypeId::argument()) {
356
0
        QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
357
0
        QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
358
0
        if (!d->message)
359
0
            return false;       // can't append this one...
360
361
0
        QDBusDemarshaller demarshaller(capabilities);
362
0
        demarshaller.message = q_dbus_message_ref(d->message);
363
364
0
        if (d->direction == Direction::Demarshalling) {
365
            // it's demarshalling; just copy
366
0
            demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
367
0
        } else {
368
            // it's marshalling; start over
369
0
            if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
370
0
                return false;   // error!
371
0
        }
372
373
0
        return appendCrossMarshalling(&demarshaller);
374
0
    }
375
376
0
    const char *signature = QDBusMetaType::typeToSignature(id);
377
0
    if (!signature) {
378
0
        unregisteredTypeError(id);
379
0
        return false;
380
0
    }
381
382
0
    switch (*signature) {
383
0
#ifdef __OPTIMIZE__
384
0
    case DBUS_TYPE_BYTE:
385
0
    case DBUS_TYPE_INT16:
386
0
    case DBUS_TYPE_UINT16:
387
0
    case DBUS_TYPE_INT32:
388
0
    case DBUS_TYPE_UINT32:
389
0
    case DBUS_TYPE_INT64:
390
0
    case DBUS_TYPE_UINT64:
391
0
    case DBUS_TYPE_DOUBLE:
392
0
        qIterAppend(&iterator, ba, *signature, arg.constData());
393
0
        return true;
394
0
    case DBUS_TYPE_BOOLEAN:
395
0
        append( arg.toBool() );
396
0
        return true;
397
#else
398
    case DBUS_TYPE_BYTE:
399
        append( qvariant_cast<uchar>(arg) );
400
        return true;
401
    case DBUS_TYPE_BOOLEAN:
402
        append( arg.toBool() );
403
        return true;
404
    case DBUS_TYPE_INT16:
405
        append( qvariant_cast<short>(arg) );
406
        return true;
407
    case DBUS_TYPE_UINT16:
408
        append( qvariant_cast<ushort>(arg) );
409
        return true;
410
    case DBUS_TYPE_INT32:
411
        append( static_cast<dbus_int32_t>(arg.toInt()) );
412
        return true;
413
    case DBUS_TYPE_UINT32:
414
        append( static_cast<dbus_uint32_t>(arg.toUInt()) );
415
        return true;
416
    case DBUS_TYPE_INT64:
417
        append( arg.toLongLong() );
418
        return true;
419
    case DBUS_TYPE_UINT64:
420
        append( arg.toULongLong() );
421
        return true;
422
    case DBUS_TYPE_DOUBLE:
423
        append( arg.toDouble() );
424
        return true;
425
#endif
426
427
0
    case DBUS_TYPE_STRING:
428
0
        append( arg.toString() );
429
0
        return true;
430
0
    case DBUS_TYPE_OBJECT_PATH:
431
0
        append( qvariant_cast<QDBusObjectPath>(arg) );
432
0
        return true;
433
0
    case DBUS_TYPE_SIGNATURE:
434
0
        append( qvariant_cast<QDBusSignature>(arg) );
435
0
        return true;
436
437
    // compound types:
438
0
    case DBUS_TYPE_VARIANT:
439
        // nested QVariant
440
0
        return append( qvariant_cast<QDBusVariant>(arg) );
441
442
0
    case DBUS_TYPE_ARRAY:
443
        // could be many things
444
        // find out what kind of array it is
445
0
        switch (arg.metaType().id()) {
446
0
        case QMetaType::QStringList:
447
0
            append( arg.toStringList() );
448
0
            return true;
449
450
0
        case QMetaType::QByteArray:
451
0
            append( arg.toByteArray() );
452
0
            return true;
453
454
0
        default:
455
0
            ;
456
0
        }
457
0
        Q_FALLTHROUGH();
458
459
0
    case DBUS_TYPE_STRUCT:
460
0
    case DBUS_STRUCT_BEGIN_CHAR:
461
0
        return appendRegisteredType( arg );
462
463
0
    case DBUS_TYPE_DICT_ENTRY:
464
0
    case DBUS_DICT_ENTRY_BEGIN_CHAR:
465
0
        qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
466
0
        return false;
467
468
0
    case DBUS_TYPE_UNIX_FD:
469
0
        if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) {
470
0
            append(qvariant_cast<QDBusUnixFileDescriptor>(arg));
471
0
            return true;
472
0
        }
473
0
        Q_FALLTHROUGH();
474
475
0
    default:
476
0
        qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-Bus type '%s'",
477
0
                 signature);
478
0
        return false;
479
0
    }
480
481
0
    return true;
482
0
}
483
484
bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
485
0
{
486
0
    ref.ref();                  // reference up
487
0
    QDBusArgument self(QDBusArgumentPrivate::create(this));
488
0
    return QDBusMetaType::marshall(self, arg.metaType(), arg.constData());
489
0
}
490
491
bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
492
0
{
493
0
    int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
494
0
    if (QDBusUtil::isValidBasicType(code)) {
495
        // easy: just append
496
        // do exactly like the D-Bus docs suggest
497
        // (see apidocs for q_dbus_message_iter_get_basic)
498
499
0
        qlonglong value;
500
0
        q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
501
0
        q_dbus_message_iter_next(&demarshaller->iterator);
502
0
        q_dbus_message_iter_append_basic(&iterator, code, &value);
503
0
        return true;
504
0
    }
505
506
0
    if (code == DBUS_TYPE_ARRAY) {
507
0
        int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
508
0
        if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) {
509
            // another optimization: fixed size arrays
510
            // code is exactly like QDBusDemarshaller::toByteArray
511
0
            DBusMessageIter sub;
512
0
            q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
513
0
            q_dbus_message_iter_next(&demarshaller->iterator);
514
0
            int len;
515
0
            void* data;
516
0
            q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
517
518
0
            char signature[2] = { char(element), 0 };
519
0
            q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
520
0
            q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
521
0
            q_dbus_message_iter_close_container(&iterator, &sub);
522
523
0
            return true;
524
0
        }
525
0
    }
526
527
    // We have to recurse
528
0
    QDBusDemarshaller *drecursed = demarshaller->beginCommon();
529
530
0
    QDBusMarshaller mrecursed(capabilities);  // create on the stack makes it autoclose
531
0
    QByteArray subSignature;
532
0
    const char *sig = nullptr;
533
0
    if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
534
0
        subSignature = drecursed->currentSignature().toLatin1();
535
0
        if (!subSignature.isEmpty())
536
0
            sig = subSignature.constData();
537
0
    }
538
0
    open(mrecursed, code, sig);
539
540
0
    while (!drecursed->atEnd()) {
541
0
        if (!mrecursed.appendCrossMarshalling(drecursed)) {
542
0
            delete drecursed;
543
0
            return false;
544
0
        }
545
0
    }
546
547
0
    delete drecursed;
548
0
    return true;
549
0
}
550
551
QT_END_NAMESPACE
552
553
#endif // QT_NO_DBUS