Coverage Report

Created: 2025-11-11 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dbus-broker/subprojects/libcdvar-1/src/c-dvar.h
Line
Count
Source
1
#pragma once
2
3
/*
4
 * D-Bus Variant Type-System
5
 *
6
 * This library implements the D-Bus type-system as a variant type, including
7
 * marshalling and demarshalling functionality. It is fully implemented in
8
 * ISO-C11 and has no external dependencies.
9
 *
10
 * This type-system strictly adheres to the D-Bus spec, including its
11
 * limitations in size and depth. Unlike the related GVariant type-system, it
12
 * is not suitable for use outside of D-Bus. Hence, this implementation does
13
 * not strive to be universally applicable, but solely meant to be used with
14
 * D-Bus IPC.
15
 */
16
17
#ifdef __cplusplus
18
extern "C" {
19
#endif
20
21
#include <endian.h>
22
#include <errno.h>
23
#include <inttypes.h>
24
#include <stdarg.h>
25
#include <stdbool.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
typedef struct CDVar CDVar;
30
typedef struct CDVarLevel CDVarLevel;
31
typedef struct CDVarType CDVarType;
32
33
/**
34
 * C_DVAR_TYPE_LENGTH_MAX - Maximum length of a type signature
35
 *
36
 * Every valid D-Bus Type has a string representation, called its type
37
 * signature. The maximum length of such a signature of a single complete type
38
 * is defined by the D-Bus specification to be 255. The original limit only
39
 * affects the maximum length of a signature of concatenated types. This,
40
 * however, implies that a single type has the same limit.
41
 *
42
 * No signature of any type can ever exceed this length. There is no intention
43
 * to every support longer signatures. If bigger types are needed, you better
44
 * use a non-deprecated serialization like GVariant.
45
 */
46
#define C_DVAR_TYPE_LENGTH_MAX (255)
47
48
/**
49
 * C_DVAR_TYPE_DEPTH_MAX - Maximum depth of a type signature
50
 *
51
 * Similar to C_DVAR_TYPE_LENGTH_MAX, this limits the complexity of any valid
52
 * type signature. This limits the maximum depth of containers to 64. It is
53
 * defined by the D-Bus specification and enforced by this implementation. The
54
 * specification further restricts the depth among the different container
55
 * types. See the specification for details.
56
 *
57
 * No signature of any type can ever exceed this depth. There is no intention
58
 * to every support deeper signatures. If needed, you better use a
59
 * non-deprecated serialization like GVariant.
60
 */
61
#define C_DVAR_TYPE_DEPTH_MAX (64)
62
63
enum {
64
        _C_DVAR_E_SUCCESS,
65
66
        /* type/signature errors */
67
        C_DVAR_E_OVERLONG_TYPE,
68
        C_DVAR_E_DEPTH_OVERFLOW,
69
        C_DVAR_E_INVALID_TYPE,
70
71
        /* data errors */
72
        C_DVAR_E_CORRUPT_DATA,
73
        C_DVAR_E_OUT_OF_BOUNDS,
74
        C_DVAR_E_TYPE_MISMATCH,
75
};
76
77
/**
78
 * struct CDVarType - D-Bus Type Information
79
 * @size:               size in bytes required for the serialization, 0 if dynamic
80
 * @alignment:          required alignment, given as power of 2
81
 * @element:            character code of this entry
82
 * @length:             length of the full type, given as number of entries
83
 * @basic:              whether this is a basic type
84
 *
85
 * Every valid D-Bus Type can be parsed into an array of CDVarType objects,
86
 * containing detailed information about the type. The length of a parsed
87
 * CDVarType array is the same as the length of the same type signature. That
88
 * is, each character code in the type signature is parsed into a CDVarType
89
 * object, based on its position in the signature.
90
 *
91
 * A CDVarType array contains recursive type-information for all sub-types of a
92
 * valid type signature. For instance, the type array of '{sv}' is found
93
 * unmodified in the type array of '(ua{sv})' at offset 3.
94
 */
95
struct CDVarType {
96
        uint32_t size : 11;
97
        uint32_t alignment : 2;
98
        uint32_t element : 7;
99
        uint32_t length : 8;
100
        uint32_t basic : 1;
101
        uint32_t __padding : 3;
102
};
103
104
/**
105
 * struct CDVarLevel - D-Bus Variant Level information
106
 * @parent_types:               type information of the parent signature
107
 * @i_type:                     current type position in parent signature
108
 * @n_parent_types:             number of single complete types in @parent_types
109
 * @n_type:                     remaining length after @i_type
110
 * @container:                  cached parent container element
111
 * @allocated_parent_types:     whether @parent_types is owned and allocated
112
 * @i_buffer:                   current data position
113
 * @n_buffer:                   remaining length after @i_buffer
114
 * @index:                      cached container-dependent index
115
 */
116
struct CDVarLevel {
117
        CDVarType *parent_types;
118
        CDVarType *i_type;
119
        uint8_t n_parent_types;
120
        uint8_t n_type;
121
        uint8_t container : 7;
122
        uint8_t allocated_parent_types : 1;
123
        size_t i_buffer;
124
        union {
125
                /* reader */
126
                size_t n_buffer;
127
                /* writer */
128
                size_t index;
129
        };
130
};
131
132
/**
133
 * struct CDVar - D-Bus Variant
134
 * @data:               data buffer to parse or write
135
 * @n_data:             length of @data in bytes
136
 * @poison:             current object poison error code, or 0
137
 * @n_root_type:        cached total signature length of the root type
138
 * @ro:                 object is read-only
139
 * @big_endian:         data is provided as big-endian
140
 * @current:            current level position
141
 * @levels:             container levels
142
 */
143
struct CDVar {
144
        uint8_t *data;
145
        size_t n_data;
146
147
        int poison;
148
        uint8_t n_root_type;
149
        bool ro : 1;
150
        bool big_endian : 1;
151
152
        CDVarLevel *current;
153
        CDVarLevel levels[C_DVAR_TYPE_DEPTH_MAX + 1];
154
};
155
156
11.2k
#define C_DVAR_INIT { .big_endian = !!(__BYTE_ORDER == __BIG_ENDIAN) }
157
158
/* builtin */
159
160
#define C_DVAR_TYPE_y (1, 0, 'y', 1, 1)
161
#define C_DVAR_TYPE_b (4, 2, 'b', 1, 1)
162
#define C_DVAR_TYPE_n (2, 1, 'n', 1, 1)
163
#define C_DVAR_TYPE_q (2, 1, 'q', 1, 1)
164
#define C_DVAR_TYPE_i (4, 2, 'i', 1, 1)
165
#define C_DVAR_TYPE_u (4, 2, 'u', 1, 1)
166
#define C_DVAR_TYPE_x (8, 3, 'x', 1, 1)
167
#define C_DVAR_TYPE_t (8, 3, 't', 1, 1)
168
#define C_DVAR_TYPE_h (4, 2, 'h', 1, 1)
169
#define C_DVAR_TYPE_d (8, 3, 'd', 1, 1)
170
#define C_DVAR_TYPE_s (0, 2, 's', 1, 1)
171
#define C_DVAR_TYPE_o (0, 2, 'o', 1, 1)
172
#define C_DVAR_TYPE_g (0, 0, 'g', 1, 1)
173
#define C_DVAR_TYPE_v (0, 0, 'v', 1, 0)
174
175
extern const CDVarType c_dvar_type_y[];
176
extern const CDVarType c_dvar_type_b[];
177
extern const CDVarType c_dvar_type_n[];
178
extern const CDVarType c_dvar_type_q[];
179
extern const CDVarType c_dvar_type_i[];
180
extern const CDVarType c_dvar_type_u[];
181
extern const CDVarType c_dvar_type_x[];
182
extern const CDVarType c_dvar_type_t[];
183
extern const CDVarType c_dvar_type_h[];
184
extern const CDVarType c_dvar_type_d[];
185
extern const CDVarType c_dvar_type_s[];
186
extern const CDVarType c_dvar_type_o[];
187
extern const CDVarType c_dvar_type_g[];
188
extern const CDVarType c_dvar_type_v[];
189
extern const CDVarType c_dvar_type_unit[];
190
191
/* type handling */
192
193
int c_dvar_type_new_from_signature(CDVarType **typep, const char *signature, size_t n_signature);
194
CDVarType *c_dvar_type_free(CDVarType *type);
195
196
int c_dvar_type_compare_string(const CDVarType *subject, const char *object, size_t n_object);
197
198
/* variant management */
199
200
int c_dvar_new(CDVar **varp);
201
CDVar *c_dvar_free(CDVar *var);
202
void c_dvar_init(CDVar *var);
203
void c_dvar_deinit(CDVar *var);
204
205
bool c_dvar_is_big_endian(CDVar *var);
206
int c_dvar_get_poison(CDVar *var);
207
void c_dvar_get_data(CDVar *var, void **datap, size_t *n_datap);
208
void c_dvar_get_root_types(CDVar *var, const CDVarType **typesp, size_t *n_typesp);
209
void c_dvar_get_parent_types(CDVar *var, const CDVarType **typesp, size_t *n_typesp);
210
211
void c_dvar_begin_read(CDVar *var, bool big_endian, const CDVarType *types, size_t n_types, const void *data, size_t n_data);
212
bool c_dvar_more(CDVar *var);
213
int c_dvar_vread(CDVar *var, const char *format, va_list args);
214
int c_dvar_vskip(CDVar *var, const char *format, va_list args);
215
int c_dvar_end_read(CDVar *var);
216
217
bool c_dvar_is_path(const char *string, size_t n_string);
218
219
void c_dvar_begin_write(CDVar *var, bool big_endian, const CDVarType *types, size_t n_types);
220
int c_dvar_vwrite(CDVar *var, const char *format, va_list args);
221
int c_dvar_end_write(CDVar *var, void **datap, size_t *n_datap);
222
223
/* inline helpers */
224
225
/**
226
 * c_dvar_type_new_from_string() - allocate new type information from string
227
 * @typep:              output argument for newly allocated object
228
 * @str:                string representation of the type
229
 *
230
 * This is similar to c_dvar_type_new_from_signature(), but it fails if @str is
231
 * not a single complete type. In case @str contains more than a single
232
 * complete type, C_DVAR_E_INVALID_TYPE is returned.
233
 *
234
 * Return: 0 on success, negative error code on fatal failure, positive error
235
 *         code on parser errors.
236
 */
237
0
static inline int c_dvar_type_new_from_string(CDVarType **typep, const char *str) {
238
0
        CDVarType *type = *typep ? : NULL;
239
0
        size_t n;
240
0
        int r;
241
0
242
0
        n = strlen(str);
243
0
        r = c_dvar_type_new_from_signature(&type, str, n);
244
0
        if (r)
245
0
                return r;
246
0
247
0
        if (n != type->length) {
248
0
                if (!*typep)
249
0
                        c_dvar_type_free(type);
250
0
                return C_DVAR_E_INVALID_TYPE;
251
0
        }
252
0
253
0
        *typep = type;
254
0
        return 0;
255
0
256
0
}
Unexecuted instantiation: message.c:c_dvar_type_new_from_string
Unexecuted instantiation: c-dvar.c:c_dvar_type_new_from_string
Unexecuted instantiation: c-dvar-reader.c:c_dvar_type_new_from_string
Unexecuted instantiation: c-dvar-type.c:c_dvar_type_new_from_string
257
258
/**
259
 * c_dvar_type_freep() - free type information
260
 * @type:               type information to free
261
 *
262
 * This is the cleanup-helper for c_dvar_type_free().
263
 */
264
12.1k
static inline void c_dvar_type_freep(CDVarType **type) {
265
12.1k
        if (*type)
266
0
                c_dvar_type_free(*type);
267
12.1k
}
Unexecuted instantiation: message.c:c_dvar_type_freep
Unexecuted instantiation: c-dvar.c:c_dvar_type_freep
Unexecuted instantiation: c-dvar-reader.c:c_dvar_type_freep
c-dvar-type.c:c_dvar_type_freep
Line
Count
Source
264
12.1k
static inline void c_dvar_type_freep(CDVarType **type) {
265
12.1k
        if (*type)
266
0
                c_dvar_type_free(*type);
267
12.1k
}
268
269
/**
270
 * c_dvar_freep() - free variant
271
 * @var:                variant to free
272
 *
273
 * This is the cleanup-helper for c_dvar_free().
274
 */
275
0
static inline void c_dvar_freep(CDVar **var) {
276
0
        if (*var)
277
0
                c_dvar_free(*var);
278
0
}
Unexecuted instantiation: message.c:c_dvar_freep
Unexecuted instantiation: c-dvar.c:c_dvar_freep
Unexecuted instantiation: c-dvar-reader.c:c_dvar_freep
Unexecuted instantiation: c-dvar-type.c:c_dvar_freep
279
280
/**
281
 * c_dvar_deinitp() - reset variant
282
 * @var:                variant to reset
283
 *
284
 * This is the cleanup-helper for c_dvar_deinit().
285
 */
286
0
static inline void c_dvar_deinitp(CDVar **var) {
287
0
        if (*var)
288
0
                c_dvar_deinit(*var);
289
0
}
Unexecuted instantiation: message.c:c_dvar_deinitp
Unexecuted instantiation: c-dvar.c:c_dvar_deinitp
Unexecuted instantiation: c-dvar-reader.c:c_dvar_deinitp
Unexecuted instantiation: c-dvar-type.c:c_dvar_deinitp
290
291
/**
292
 * c_dvar_read() - read data from variant
293
 * @var:                variant to operate on
294
 * @format:             format string
295
 *
296
 * This is the va_arg-based equivalent of c_dvar_vread(). See its documentation
297
 * for details.
298
 *
299
 * Return: 0 on success, negative error code on fatal errors, positive error
300
 *         code on parser failure.
301
 */
302
154k
static inline int c_dvar_read(CDVar *var, const char *format, ...) {
303
154k
        va_list args;
304
154k
        int r;
305
306
154k
        va_start(args, format);
307
154k
        r = c_dvar_vread(var, format, args);
308
154k
        va_end(args);
309
154k
        return r;
310
154k
}
message.c:c_dvar_read
Line
Count
Source
302
16.0k
static inline int c_dvar_read(CDVar *var, const char *format, ...) {
303
16.0k
        va_list args;
304
16.0k
        int r;
305
306
16.0k
        va_start(args, format);
307
16.0k
        r = c_dvar_vread(var, format, args);
308
        va_end(args);
309
16.0k
        return r;
310
16.0k
}
Unexecuted instantiation: c-dvar.c:c_dvar_read
c-dvar-reader.c:c_dvar_read
Line
Count
Source
302
138k
static inline int c_dvar_read(CDVar *var, const char *format, ...) {
303
138k
        va_list args;
304
138k
        int r;
305
306
138k
        va_start(args, format);
307
138k
        r = c_dvar_vread(var, format, args);
308
        va_end(args);
309
138k
        return r;
310
138k
}
Unexecuted instantiation: c-dvar-type.c:c_dvar_read
311
312
/**
313
 * c_dvar_skip() - skip over data from variant
314
 * @var:                variant to operate on
315
 * @format:             format string
316
 *
317
 * This is the va_arg-based equivalent of c_dvar_vskip(). See its documentation
318
 * for details.
319
 *
320
 * Return: 0 on success, negative error code on fatal errors, positive error
321
 *         code on parser failure.
322
 */
323
10.6k
static inline int c_dvar_skip(CDVar *var, const char *format, ...) {
324
10.6k
        va_list args;
325
10.6k
        int r;
326
327
10.6k
        va_start(args, format);
328
10.6k
        r = c_dvar_vskip(var, format, args);
329
10.6k
        va_end(args);
330
10.6k
        return r;
331
10.6k
}
message.c:c_dvar_skip
Line
Count
Source
323
10.6k
static inline int c_dvar_skip(CDVar *var, const char *format, ...) {
324
10.6k
        va_list args;
325
10.6k
        int r;
326
327
10.6k
        va_start(args, format);
328
10.6k
        r = c_dvar_vskip(var, format, args);
329
        va_end(args);
330
10.6k
        return r;
331
10.6k
}
Unexecuted instantiation: c-dvar.c:c_dvar_skip
Unexecuted instantiation: c-dvar-reader.c:c_dvar_skip
Unexecuted instantiation: c-dvar-type.c:c_dvar_skip
332
333
/**
334
 * c_dvar_write() - write data to variant
335
 * @var:                variant to operate on
336
 * @format:             format string
337
 *
338
 * This is the va_arg-based equivalent of c_dvar_vwrite(). See its
339
 * documentation for details.
340
 *
341
 * Return: 0 on success, negative error code on fatal errors, positive error
342
 *         code on builder failure.
343
 */
344
0
static inline int c_dvar_write(CDVar *var, const char *format, ...) {
345
0
        va_list args;
346
0
        int r;
347
0
348
0
        va_start(args, format);
349
0
        r = c_dvar_vwrite(var, format, args);
350
0
        va_end(args);
351
0
        return r;
352
0
}
Unexecuted instantiation: message.c:c_dvar_write
Unexecuted instantiation: c-dvar.c:c_dvar_write
Unexecuted instantiation: c-dvar-reader.c:c_dvar_write
Unexecuted instantiation: c-dvar-type.c:c_dvar_write
353
354
#ifdef __cplusplus
355
}
356
#endif