Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/dbus/qdbusmisc.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 <string.h>
6
7
#ifndef QT_BOOTSTRAPPED
8
#include <QtCore/qcoreapplication.h>
9
#include <QtCore/qlist.h>
10
#include <QtCore/qmetaobject.h>
11
#include <QtCore/qvariant.h>
12
#include <private/qurl_p.h>
13
14
#include "qdbusutil_p.h"
15
#include "qdbusconnection_p.h"
16
#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
17
#endif
18
#include "qdbusmetatype_p.h"
19
20
#ifndef QT_NO_DBUS
21
22
QT_BEGIN_NAMESPACE
23
24
using namespace Qt::StringLiterals;
25
26
bool qDBusCheckAsyncTag(const char *tag)
27
0
{
28
0
    static const char noReplyTag[] = "Q_NOREPLY";
29
0
    if (!tag || !*tag)
30
0
        return false;
31
32
0
    const char *p = strstr(tag, noReplyTag);
33
0
    if (p != nullptr &&
34
0
        (p == tag || *(p-1) == ' ') &&
35
0
        (p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' '))
36
0
        return true;
37
38
0
    return false;
39
0
}
40
41
#ifndef QT_BOOTSTRAPPED
42
43
QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
44
0
{
45
0
    QString interface;
46
47
0
    int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
48
0
    if (idx >= mo->classInfoOffset()) {
49
0
        interface = QLatin1StringView(mo->classInfo(idx).value());
50
0
    } else {
51
0
        interface = QLatin1StringView(mo->className());
52
0
        interface.replace("::"_L1, "."_L1);
53
54
0
        if (interface.startsWith("QDBus"_L1)) {
55
0
            interface.prepend("org.qtproject.QtDBus."_L1);
56
0
        } else if (interface.startsWith(u'Q') &&
57
0
                   interface.size() >= 2 && interface.at(1).isUpper()) {
58
            // assume it's Qt
59
0
            interface.prepend("org.qtproject.Qt."_L1);
60
0
        } else if (!QCoreApplication::instance()||
61
0
                   QCoreApplication::instance()->applicationName().isEmpty()) {
62
0
            interface.prepend("local."_L1);
63
0
        } else {
64
0
            QString domainName = QCoreApplication::instance()->applicationName();
65
0
            const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
66
0
            if (organizationDomain.isEmpty())
67
0
                domainName.append(".local"_L1);
68
0
            else
69
0
                domainName.append(u'.').append(organizationDomain);
70
71
            // Domain names used to produce interface names should be IDN-encoded.
72
0
            QString encodedDomainName = qt_ACE_do(domainName, ToAceOnly, ForbidLeadingDot);
73
0
            if (encodedDomainName.isEmpty()) {
74
0
                interface.prepend("local."_L1);
75
0
                return interface;
76
0
            }
77
78
            // Hyphens are not allowed in interface names and should be replaced
79
            // by underscores.
80
0
            encodedDomainName.replace(u'-', u'_');
81
82
0
            auto nameParts = QStringView{ encodedDomainName }.split(u'.', Qt::SkipEmptyParts);
83
84
0
            QString composedDomain;
85
            // + 1 for additional dot, e.g. domainName equals "App.example.com",
86
            // then composedDomain will be equal "com.example.App."
87
0
            composedDomain.reserve(encodedDomainName.size() + nameParts.size() + 1);
88
0
            for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) {
89
                // An interface name cannot start with a digit, and cannot
90
                // contain digits immediately following a period. Prefix such
91
                // digits with underscores.
92
0
                if (it->first().isDigit())
93
0
                    composedDomain += u'_';
94
0
                composedDomain += *it + u'.';
95
0
            }
96
97
0
            interface.prepend(composedDomain);
98
0
        }
99
0
     }
100
101
0
    return interface;
102
0
}
103
104
bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
105
0
{
106
0
    const QMetaObject *mo = obj->metaObject();
107
0
    for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
108
0
        if (interface_name == qDBusInterfaceFromMetaObject(mo))
109
0
            return true;
110
0
    return false;
111
0
}
112
113
// calculates the metatypes for the method
114
// the slot must have the parameters in the following form:
115
//  - zero or more value or const-ref parameters of any kind
116
//  - zero or one const ref of QDBusMessage
117
//  - zero or more non-const ref parameters
118
// No parameter may be a template.
119
// this function returns -1 if the parameters don't match the above form
120
// this function returns the number of *input* parameters, including the QDBusMessage one if any
121
// this function does not check the return type, so metaTypes[0] is always 0 and always present
122
// metaTypes.count() >= retval + 1 in all cases
123
//
124
// sig must be the normalised signature for the method
125
int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
126
0
{
127
0
    QList<QByteArray> parameterTypes;
128
0
    parameterTypes.reserve(mm.parameterCount());
129
130
    // Not using QMetaMethod::parameterTypes() since we call QMetaType::fromName below
131
    // where we need any typedefs resolved already.
132
0
    for (int i = 0; i < mm.parameterCount(); ++i) {
133
0
        QByteArray typeName = mm.parameterMetaType(i).name();
134
0
        if (typeName.isEmpty())
135
0
            typeName = mm.parameterTypeName(i);
136
0
        parameterTypes.append(typeName);
137
0
    }
138
139
0
    return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg);
140
0
}
141
142
#endif // QT_BOOTSTRAPPED
143
144
int qDBusParametersForMethod(const QList<QByteArray> &parameterTypes, QList<QMetaType> &metaTypes,
145
                             QString &errorMsg)
146
0
{
147
0
    QDBusMetaTypeId::init();
148
0
    metaTypes.clear();
149
150
0
    metaTypes.append(QMetaType());        // return type
151
0
    int inputCount = 0;
152
0
    bool seenMessage = false;
153
0
    for (QByteArray type : parameterTypes) {
154
0
        if (type.endsWith('*')) {
155
0
            errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type);
156
0
            return -1;
157
0
        }
158
159
0
        if (type.endsWith('&')) {
160
0
            QByteArray basictype = type;
161
0
            basictype.truncate(type.size() - 1);
162
163
0
            QMetaType id = QMetaType::fromName(basictype);
164
0
            if (!id.isValid()) {
165
0
                errorMsg = "Unregistered output type in parameter list: "_L1 + QLatin1StringView(type);
166
0
                return -1;
167
0
            } else if (QDBusMetaType::typeToSignature(id) == nullptr)
168
0
                return -1;
169
170
0
            metaTypes.append(id);
171
0
            seenMessage = true; // it cannot appear anymore anyways
172
0
            continue;
173
0
        }
174
175
0
        if (seenMessage) {      // && !type.endsWith('&')
176
0
            errorMsg = "Invalid method, non-output parameters after message or after output parameters: "_L1 + QLatin1StringView(type);
177
0
            return -1;          // not allowed
178
0
        }
179
180
0
        if (type.startsWith("QVector<"))
181
0
            type = "QList<" + type.mid(sizeof("QVector<") - 1);
182
183
0
        QMetaType id = QMetaType::fromName(type);
184
#ifdef QT_BOOTSTRAPPED
185
        // in bootstrap mode QDBusMessage isn't included, thus we need to resolve it manually here
186
        if (type == "QDBusMessage") {
187
            id = QDBusMetaTypeId::message();
188
        }
189
#endif
190
191
0
        if (!id.isValid()) {
192
0
            errorMsg = "Unregistered input type in parameter list: "_L1 + QLatin1StringView(type);
193
0
            return -1;
194
0
        }
195
196
0
        if (id == QDBusMetaTypeId::message())
197
0
            seenMessage = true;
198
0
        else if (QDBusMetaType::typeToSignature(id) == nullptr) {
199
0
            errorMsg = "Type not registered with QtDBus in parameter list: "_L1 + QLatin1StringView(type);
200
0
            return -1;
201
0
        }
202
203
0
        metaTypes.append(id);
204
0
        ++inputCount;
205
0
    }
206
207
0
    return inputCount;
208
0
}
209
210
QT_END_NAMESPACE
211
212
#endif // QT_NO_DBUS