Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/dbus/qdbusunixfiledescriptor.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
6
#include "qdbusunixfiledescriptor.h"
7
8
#ifdef Q_OS_UNIX
9
# include <private/qcore_unix_p.h>
10
#endif
11
12
QT_BEGIN_NAMESPACE
13
14
#ifndef QT_NO_DBUS
15
16
QT_IMPL_METATYPE_EXTERN(QDBusUnixFileDescriptor)
17
18
/*!
19
    \class QDBusUnixFileDescriptor
20
    \inmodule QtDBus
21
    \ingroup shared
22
    \since 4.8
23
24
    \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor.
25
26
    The QDBusUnixFileDescriptor class is used to hold one Unix file
27
    descriptor for use with the Qt D-Bus module. This allows applications to
28
    send and receive Unix file descriptors over the D-Bus connection, mapping
29
    automatically to the D-Bus type 'h'.
30
31
    Objects of type QDBusUnixFileDescriptors can be used also as parameters
32
    in signals and slots that get exported to D-Bus by registering with
33
    QDBusConnection::registerObject.
34
35
    QDBusUnixFileDescriptor does not take ownership of the file descriptor.
36
    Instead, it will use the Unix system call \c dup(2) to make a copy of the
37
    file descriptor. This file descriptor belongs to the
38
    QDBusUnixFileDescriptor object and should not be stored or closed by the
39
    user. Instead, you should make your own copy if you need that.
40
41
    \section2 Availability
42
43
    Unix file descriptor passing is not available in all D-Bus connections.
44
    This feature is present with D-Bus library and bus daemon version 1.4 and
45
    upwards on Unix systems. Qt D-Bus automatically enables the feature if such
46
    a version was found at compile-time and run-time.
47
48
    To verify that your connection does support passing file descriptors,
49
    check if the QDBusConnection::UnixFileDescriptorPassing capability is set
50
    with QDBusConnection::connectionCapabilities(). If the flag is not
51
    active, then you will not be able to make calls to methods that have
52
    QDBusUnixFileDescriptor as arguments or even embed such a type in a
53
    variant. You will also not receive calls containing that type.
54
55
    Note also that remote applications may not have support for Unix file
56
    descriptor passing. If you make a D-Bus to a remote application that
57
    cannot receive such a type, you will receive an error reply. If you try
58
    to send a signal containing a D-Bus file descriptor or return one from a
59
    method call, the message will be silently dropped.
60
61
    Even if the feature is not available, QDBusUnixFileDescriptor will
62
    continue to operate, so code need not have compile-time checks for the
63
    availability of this feature.
64
65
    On non-Unix systems, QDBusUnixFileDescriptor will always report an
66
    invalid state and QDBusUnixFileDescriptor::isSupported() will return
67
    false.
68
69
    \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities()
70
*/
71
72
/*!
73
    \typedef QDBusUnixFileDescriptor::Data
74
    \internal
75
*/
76
77
/*!
78
    \variable QDBusUnixFileDescriptor::d
79
    \internal
80
*/
81
82
class QDBusUnixFileDescriptorPrivate : public QSharedData {
83
public:
84
0
    QDBusUnixFileDescriptorPrivate() : fd(-1) { }
85
    QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
86
0
        : QSharedData(other), fd(-1)
87
0
    {  }
88
    ~QDBusUnixFileDescriptorPrivate();
89
90
    QAtomicInt fd;
91
};
92
93
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDBusUnixFileDescriptorPrivate)
94
95
/*!
96
    Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor.
97
    This is equivalent to constructing the object with an invalid file
98
    descriptor (like -1).
99
100
    \sa fileDescriptor(), isValid()
101
*/
102
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
103
0
    : d(nullptr)
104
0
{
105
0
}
106
107
/*!
108
    Constructs a QDBusUnixFileDescriptor object by copying the \a
109
    fileDescriptor parameter. The original file descriptor is not touched and
110
    must be closed by the user.
111
112
    Note that the value returned by fileDescriptor() will be different from
113
    the \a fileDescriptor parameter passed.
114
115
    If the \a fileDescriptor parameter is not valid, isValid() will return
116
    false and fileDescriptor() will return -1.
117
118
    \sa setFileDescriptor(), fileDescriptor()
119
*/
120
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
121
0
    : d(nullptr)
122
0
{
123
0
    if (fileDescriptor != -1)
124
0
        setFileDescriptor(fileDescriptor);
125
0
}
126
127
/*!
128
    Constructs a QDBusUnixFileDescriptor object by copying \a other.
129
*/
130
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other)
131
0
    : d(other.d)
132
0
{
133
0
}
134
135
/*!
136
    Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor
137
    object. If the current object contained a file descriptor, it will be
138
    properly disposed of before.
139
*/
140
QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
141
0
{
142
0
    if (this != &other)
143
0
        d.operator=(other.d);
144
0
    return *this;
145
0
}
146
147
/*!
148
   \fn QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(QDBusUnixFileDescriptor &&other)
149
150
   Move-assigns  \a other to this QDBusUnixFileDescriptor.
151
*/
152
153
/*!
154
    Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
155
*/
156
QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
157
0
{
158
0
}
159
160
/*!
161
    \fn void QDBusUnixFileDescriptor::swap(QDBusUnixFileDescriptor &other)
162
    \since 5.0
163
    \memberswap{file descriptor instance}
164
*/
165
166
/*!
167
    Returns \c true if this Unix file descriptor is valid. A valid Unix file
168
    descriptor is not -1.
169
170
    \sa fileDescriptor()
171
*/
172
bool QDBusUnixFileDescriptor::isValid() const
173
0
{
174
0
    return d ? d->fd.loadRelaxed() != -1 : false;
175
0
}
176
177
/*!
178
    Returns the Unix file descriptor contained by this
179
    QDBusUnixFileDescriptor object. An invalid file descriptor is represented
180
    by the value -1.
181
182
    Note that the file descriptor returned by this function is owned by the
183
    QDBusUnixFileDescriptor object and must not be stored past the lifetime
184
    of this object. It is ok to use it while this object is valid, but if one
185
    wants to store it for longer use, the file descriptor should be cloned
186
    using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
187
188
    \sa isValid()
189
*/
190
int QDBusUnixFileDescriptor::fileDescriptor() const
191
0
{
192
0
    return d ? d->fd.loadRelaxed() : -1;
193
0
}
194
195
// actual implementation
196
#ifdef Q_OS_UNIX
197
198
// qdoc documentation is generated on Unix
199
200
/*!
201
    Returns \c true if Unix file descriptors are supported on this platform. In
202
    other words, this function returns \c true if this is a Unix platform.
203
204
    Note that QDBusUnixFileDescriptor continues to operate even if this
205
    function returns \c false. The only difference is that the
206
    QDBusUnixFileDescriptor objects will always be in the isValid() == false
207
    state and fileDescriptor() will always return -1. The class will not
208
    consume any operating system resources.
209
*/
210
bool QDBusUnixFileDescriptor::isSupported()
211
0
{
212
0
    return true;
213
0
}
214
215
/*!
216
    Sets the file descriptor that this QDBusUnixFileDescriptor object holds
217
    to a copy of \a fileDescriptor. The original file descriptor is not
218
    touched and must be closed by the user.
219
220
    Note that the value returned by fileDescriptor() will be different from
221
    the \a fileDescriptor parameter passed.
222
223
    If the \a fileDescriptor parameter is not valid, isValid() will return
224
    false and fileDescriptor() will return -1.
225
226
    \sa isValid(), fileDescriptor()
227
*/
228
void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
229
0
{
230
0
    if (fileDescriptor != -1)
231
0
        giveFileDescriptor(qt_safe_dup(fileDescriptor));
232
0
}
233
234
/*!
235
    \internal
236
    Sets the Unix file descriptor to \a fileDescriptor without copying.
237
238
    \sa setFileDescriptor()
239
*/
240
void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
241
0
{
242
    // if we are the sole ref, d remains unchanged
243
    // if detaching happens, d->fd will be -1
244
0
    if (d)
245
0
        d.detach();
246
0
    else
247
0
        d = new QDBusUnixFileDescriptorPrivate;
248
249
0
    const int fdl = d->fd.loadRelaxed();
250
0
    if (fdl != -1)
251
0
        qt_safe_close(fdl);
252
253
0
    if (fileDescriptor != -1)
254
0
        d->fd.storeRelaxed(fileDescriptor);
255
0
}
256
257
/*!
258
    \internal
259
    Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
260
    and transfers ownership.
261
262
    Note: since QDBusUnixFileDescriptor is implicitly shared, this function
263
    is inherently racy and should be avoided.
264
*/
265
int QDBusUnixFileDescriptor::takeFileDescriptor()
266
0
{
267
0
    if (!d)
268
0
        return -1;
269
270
0
    return d->fd.fetchAndStoreRelaxed(-1);
271
0
}
272
273
QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
274
0
{
275
0
    const int fdl = fd.loadRelaxed();
276
0
    if (fdl != -1)
277
0
        qt_safe_close(fdl);
278
0
}
279
280
#else
281
bool QDBusUnixFileDescriptor::isSupported()
282
{
283
    return false;
284
}
285
286
void QDBusUnixFileDescriptor::setFileDescriptor(int)
287
{
288
}
289
290
void QDBusUnixFileDescriptor::giveFileDescriptor(int)
291
{
292
}
293
294
int QDBusUnixFileDescriptor::takeFileDescriptor()
295
{
296
    return -1;
297
}
298
299
QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
300
{
301
}
302
303
#endif
304
305
#endif // QT_NO_DBUS
306
307
QT_END_NAMESPACE