Bug Summary

File:build-scan/../src/libsystemd/sd-bus/bus-match.c
Warning:line 1079, column 17
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bus-match.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/libsystemd/libsystemd_static.a.p -I src/libsystemd -I ../src/libsystemd -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/libsystemd/sd-bus/bus-match.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3***/
4
5#include <stdio_ext.h>
6
7#include "alloc-util.h"
8#include "bus-internal.h"
9#include "bus-match.h"
10#include "bus-message.h"
11#include "bus-util.h"
12#include "fd-util.h"
13#include "fileio.h"
14#include "hexdecoct.h"
15#include "string-util.h"
16#include "strv.h"
17
18/* Example:
19 *
20 * A: type=signal,sender=foo,interface=bar
21 * B: type=signal,sender=quux,interface=fips
22 * C: type=signal,sender=quux,interface=waldo
23 * D: type=signal,member=test
24 * E: sender=miau
25 * F: type=signal
26 * G: type=signal
27 *
28 * results in this tree:
29 *
30 * BUS_MATCH_ROOT
31 * + BUS_MATCH_MESSAGE_TYPE
32 * | ` BUS_MATCH_VALUE: value == signal
33 * | + DBUS_MATCH_SENDER
34 * | | + BUS_MATCH_VALUE: value == foo
35 * | | | ` DBUS_MATCH_INTERFACE
36 * | | | ` BUS_MATCH_VALUE: value == bar
37 * | | | ` BUS_MATCH_LEAF: A
38 * | | ` BUS_MATCH_VALUE: value == quux
39 * | | ` DBUS_MATCH_INTERFACE
40 * | | | BUS_MATCH_VALUE: value == fips
41 * | | | ` BUS_MATCH_LEAF: B
42 * | | ` BUS_MATCH_VALUE: value == waldo
43 * | | ` BUS_MATCH_LEAF: C
44 * | + DBUS_MATCH_MEMBER
45 * | | ` BUS_MATCH_VALUE: value == test
46 * | | ` BUS_MATCH_LEAF: D
47 * | + BUS_MATCH_LEAF: F
48 * | ` BUS_MATCH_LEAF: G
49 * ` BUS_MATCH_SENDER
50 * ` BUS_MATCH_VALUE: value == miau
51 * ` BUS_MATCH_LEAF: E
52 */
53
54static inline bool_Bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
55 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
56}
57
58static inline bool_Bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
59 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
60 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
61 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
62}
63
64static void bus_match_node_free(struct bus_match_node *node) {
65 assert(node)do { if ((__builtin_expect(!!(!(node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node"), "../src/libsystemd/sd-bus/bus-match.c"
, 65, __PRETTY_FUNCTION__); } while (0)
;
12
Taking false branch
13
Loop condition is false. Exiting loop
66 assert(node->parent)do { if ((__builtin_expect(!!(!(node->parent)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node->parent"), "../src/libsystemd/sd-bus/bus-match.c"
, 66, __PRETTY_FUNCTION__); } while (0)
;
14
Assuming field 'parent' is non-null
15
Taking false branch
16
Loop condition is false. Exiting loop
67 assert(!node->child)do { if ((__builtin_expect(!!(!(!node->child)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("!node->child"), "../src/libsystemd/sd-bus/bus-match.c"
, 67, __PRETTY_FUNCTION__); } while (0)
;
17
Taking false branch
18
Loop condition is false. Exiting loop
68 assert(node->type != BUS_MATCH_ROOT)do { if ((__builtin_expect(!!(!(node->type != BUS_MATCH_ROOT
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->type != BUS_MATCH_ROOT"
), "../src/libsystemd/sd-bus/bus-match.c", 68, __PRETTY_FUNCTION__
); } while (0)
;
19
Taking false branch
20
Loop condition is false. Exiting loop
69 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX)do { if ((__builtin_expect(!!(!(node->type < _BUS_MATCH_NODE_TYPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->type < _BUS_MATCH_NODE_TYPE_MAX"
), "../src/libsystemd/sd-bus/bus-match.c", 69, __PRETTY_FUNCTION__
); } while (0)
;
21
Taking false branch
22
Loop condition is false. Exiting loop
70
71 if (node->parent->child) {
23
Assuming field 'child' is null
24
Taking false branch
72 /* We are apparently linked into the parent's child
73 * list. Let's remove us from there. */
74 if (node->prev) {
75 assert(node->prev->next == node)do { if ((__builtin_expect(!!(!(node->prev->next == node
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->prev->next == node"
), "../src/libsystemd/sd-bus/bus-match.c", 75, __PRETTY_FUNCTION__
); } while (0)
;
76 node->prev->next = node->next;
77 } else {
78 assert(node->parent->child == node)do { if ((__builtin_expect(!!(!(node->parent->child == node
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->parent->child == node"
), "../src/libsystemd/sd-bus/bus-match.c", 78, __PRETTY_FUNCTION__
); } while (0)
;
79 node->parent->child = node->next;
80 }
81
82 if (node->next)
83 node->next->prev = node->prev;
84 }
85
86 if (node->type == BUS_MATCH_VALUE) {
25
Assuming field 'type' is not equal to BUS_MATCH_VALUE
26
Taking false branch
87 /* We might be in the parent's hash table, so clean
88 * this up */
89
90 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
91 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8)((void *) ((uintptr_t) (node->value.u8))));
92 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
93 hashmap_remove(node->parent->compare.children, node->value.str);
94
95 free(node->value.str);
96 }
97
98 if (BUS_MATCH_IS_COMPARE(node->type)) {
27
Taking false branch
99 assert(hashmap_isempty(node->compare.children))do { if ((__builtin_expect(!!(!(hashmap_isempty(node->compare
.children))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"hashmap_isempty(node->compare.children)"), "../src/libsystemd/sd-bus/bus-match.c"
, 99, __PRETTY_FUNCTION__); } while (0)
;
100 hashmap_free(node->compare.children);
101 }
102
103 free(node);
28
Memory is released
104}
105
106static bool_Bool bus_match_node_maybe_free(struct bus_match_node *node) {
107 assert(node)do { if ((__builtin_expect(!!(!(node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node"), "../src/libsystemd/sd-bus/bus-match.c"
, 107, __PRETTY_FUNCTION__); } while (0)
;
108
109 if (node->type == BUS_MATCH_ROOT)
110 return false0;
111
112 if (node->child)
113 return false0;
114
115 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
116 return true1;
117
118 bus_match_node_free(node);
119 return true1;
120}
121
122static bool_Bool value_node_test(
123 struct bus_match_node *node,
124 enum bus_match_node_type parent_type,
125 uint8_t value_u8,
126 const char *value_str,
127 char **value_strv,
128 sd_bus_message *m) {
129
130 assert(node)do { if ((__builtin_expect(!!(!(node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node"), "../src/libsystemd/sd-bus/bus-match.c"
, 130, __PRETTY_FUNCTION__); } while (0)
;
131 assert(node->type == BUS_MATCH_VALUE)do { if ((__builtin_expect(!!(!(node->type == BUS_MATCH_VALUE
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->type == BUS_MATCH_VALUE"
), "../src/libsystemd/sd-bus/bus-match.c", 131, __PRETTY_FUNCTION__
); } while (0)
;
132
133 /* Tests parameters against this value node, doing prefix
134 * magic and stuff. */
135
136 switch (parent_type) {
137
138 case BUS_MATCH_MESSAGE_TYPE:
139 return node->value.u8 == value_u8;
140
141 case BUS_MATCH_SENDER:
142 if (streq_ptr(node->value.str, value_str))
143 return true1;
144
145 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
146 char **i;
147
148 /* on kdbus we have the well known names list
149 * in the credentials, let's make use of that
150 * for an accurate match */
151
152 STRV_FOREACH(i, m->creds.well_known_names)for ((i) = (m->creds.well_known_names); (i) && *(i
); (i)++)
153 if (streq_ptr(node->value.str, *i))
154 return true1;
155
156 } else {
157
158 /* If we don't have kdbus, we don't know the
159 * well-known names of the senders. In that,
160 * let's just hope that dbus-daemon doesn't
161 * send us stuff we didn't want. */
162
163 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
164 return true1;
165 }
166
167 return false0;
168
169 case BUS_MATCH_DESTINATION:
170 case BUS_MATCH_INTERFACE:
171 case BUS_MATCH_MEMBER:
172 case BUS_MATCH_PATH:
173 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
174
175 if (value_str)
176 return streq_ptr(node->value.str, value_str);
177
178 return false0;
179
180 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
181 char **i;
182
183 STRV_FOREACH(i, value_strv)for ((i) = (value_strv); (i) && *(i); (i)++)
184 if (streq_ptr(node->value.str, *i))
185 return true1;
186
187 return false0;
188 }
189
190 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
191 if (value_str)
192 return namespace_simple_pattern(node->value.str, value_str);
193
194 return false0;
195
196 case BUS_MATCH_PATH_NAMESPACE:
197 return path_simple_pattern(node->value.str, value_str);
198
199 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
200 if (value_str)
201 return path_complex_pattern(node->value.str, value_str);
202
203 return false0;
204
205 default:
206 assert_not_reached("Invalid node type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Invalid node type"), "../src/libsystemd/sd-bus/bus-match.c",
206, __PRETTY_FUNCTION__); } while (0)
;
207 }
208}
209
210static bool_Bool value_node_same(
211 struct bus_match_node *node,
212 enum bus_match_node_type parent_type,
213 uint8_t value_u8,
214 const char *value_str) {
215
216 /* Tests parameters against this value node, not doing prefix
217 * magic and stuff, i.e. this one actually compares the match
218 * itself. */
219
220 assert(node)do { if ((__builtin_expect(!!(!(node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node"), "../src/libsystemd/sd-bus/bus-match.c"
, 220, __PRETTY_FUNCTION__); } while (0)
;
221 assert(node->type == BUS_MATCH_VALUE)do { if ((__builtin_expect(!!(!(node->type == BUS_MATCH_VALUE
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->type == BUS_MATCH_VALUE"
), "../src/libsystemd/sd-bus/bus-match.c", 221, __PRETTY_FUNCTION__
); } while (0)
;
222
223 switch (parent_type) {
224
225 case BUS_MATCH_MESSAGE_TYPE:
226 return node->value.u8 == value_u8;
227
228 case BUS_MATCH_SENDER:
229 case BUS_MATCH_DESTINATION:
230 case BUS_MATCH_INTERFACE:
231 case BUS_MATCH_MEMBER:
232 case BUS_MATCH_PATH:
233 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
234 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
235 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
236 case BUS_MATCH_PATH_NAMESPACE:
237 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
238 return streq(node->value.str, value_str)(strcmp((node->value.str),(value_str)) == 0);
239
240 default:
241 assert_not_reached("Invalid node type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Invalid node type"), "../src/libsystemd/sd-bus/bus-match.c",
241, __PRETTY_FUNCTION__); } while (0)
;
242 }
243}
244
245int bus_match_run(
246 sd_bus *bus,
247 struct bus_match_node *node,
248 sd_bus_message *m) {
249
250 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **test_strv = NULL((void*)0);
251 const char *test_str = NULL((void*)0);
252 uint8_t test_u8 = 0;
253 int r;
254
255 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-match.c"
, 255, __PRETTY_FUNCTION__); } while (0)
;
256
257 if (!node)
258 return 0;
259
260 if (bus && bus->match_callbacks_modified)
261 return 0;
262
263 /* Not these special semantics: when traversing the tree we
264 * usually let bus_match_run() when called for a node
265 * recursively invoke bus_match_run(). There's are two
266 * exceptions here though, which are BUS_NODE_ROOT (which
267 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
268 * are invoked anyway by its parent. */
269
270 switch (node->type) {
271
272 case BUS_MATCH_ROOT:
273
274 /* Run all children. Since we cannot have any siblings
275 * we won't call any. The children of the root node
276 * are compares or leaves, they will automatically
277 * call their siblings. */
278 return bus_match_run(bus, node->child, m);
279
280 case BUS_MATCH_VALUE:
281
282 /* Run all children. We don't execute any siblings, we
283 * assume our caller does that. The children of value
284 * nodes are compares or leaves, they will
285 * automatically call their siblings */
286
287 assert(node->child)do { if ((__builtin_expect(!!(!(node->child)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("node->child"), "../src/libsystemd/sd-bus/bus-match.c"
, 287, __PRETTY_FUNCTION__); } while (0)
;
288 return bus_match_run(bus, node->child, m);
289
290 case BUS_MATCH_LEAF:
291
292 if (bus) {
293 if (node->leaf.callback->last_iteration == bus->iteration_counter)
294 return 0;
295
296 node->leaf.callback->last_iteration = bus->iteration_counter;
297 }
298
299 r = sd_bus_message_rewind(m, true1);
300 if (r < 0)
301 return r;
302
303 /* Run the callback. And then invoke siblings. */
304 if (node->leaf.callback->callback) {
305 _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error_buffer = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0});
306 sd_bus_slot *slot;
307
308 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback)__extension__ ({ const typeof( ((sd_bus_slot*)0)->match_callback
) *__unique_prefix_A16 = ((node->leaf.callback)); (sd_bus_slot
*)( (char *)__unique_prefix_A16 - __builtin_offsetof(sd_bus_slot
, match_callback) ); })
;
309 if (bus) {
310 bus->current_slot = sd_bus_slot_ref(slot);
311 bus->current_handler = node->leaf.callback->callback;
312 bus->current_userdata = slot->userdata;
313 }
314 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
315 if (bus) {
316 bus->current_userdata = NULL((void*)0);
317 bus->current_handler = NULL((void*)0);
318 bus->current_slot = sd_bus_slot_unref(slot);
319 }
320
321 r = bus_maybe_reply_error(m, r, &error_buffer);
322 if (r != 0)
323 return r;
324
325 if (bus && bus->match_callbacks_modified)
326 return 0;
327 }
328
329 return bus_match_run(bus, node->next, m);
330
331 case BUS_MATCH_MESSAGE_TYPE:
332 test_u8 = m->header->type;
333 break;
334
335 case BUS_MATCH_SENDER:
336 test_str = m->sender;
337 /* FIXME: resolve test_str from a well-known to a unique name first */
338 break;
339
340 case BUS_MATCH_DESTINATION:
341 test_str = m->destination;
342 break;
343
344 case BUS_MATCH_INTERFACE:
345 test_str = m->interface;
346 break;
347
348 case BUS_MATCH_MEMBER:
349 test_str = m->member;
350 break;
351
352 case BUS_MATCH_PATH:
353 case BUS_MATCH_PATH_NAMESPACE:
354 test_str = m->path;
355 break;
356
357 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
358 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
359 break;
360
361 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
362 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
363 break;
364
365 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
366 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
367 break;
368
369 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
370 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
371 break;
372
373 default:
374 assert_not_reached("Unknown match type.")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unknown match type."), "../src/libsystemd/sd-bus/bus-match.c"
, 374, __PRETTY_FUNCTION__); } while (0)
;
375 }
376
377 if (BUS_MATCH_CAN_HASH(node->type)) {
378 struct bus_match_node *found;
379
380 /* Lookup via hash table, nice! So let's jump directly. */
381
382 if (test_str)
383 found = hashmap_get(node->compare.children, test_str);
384 else if (test_strv) {
385 char **i;
386
387 STRV_FOREACH(i, test_strv)for ((i) = (test_strv); (i) && *(i); (i)++) {
388 found = hashmap_get(node->compare.children, *i);
389 if (found) {
390 r = bus_match_run(bus, found, m);
391 if (r != 0)
392 return r;
393 }
394 }
395
396 found = NULL((void*)0);
397 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
398 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8)((void *) ((uintptr_t) (test_u8))));
399 else
400 found = NULL((void*)0);
401
402 if (found) {
403 r = bus_match_run(bus, found, m);
404 if (r != 0)
405 return r;
406 }
407 } else {
408 struct bus_match_node *c;
409
410 /* No hash table, so let's iterate manually... */
411
412 for (c = node->child; c; c = c->next) {
413 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
414 continue;
415
416 r = bus_match_run(bus, c, m);
417 if (r != 0)
418 return r;
419
420 if (bus && bus->match_callbacks_modified)
421 return 0;
422 }
423 }
424
425 if (bus && bus->match_callbacks_modified)
426 return 0;
427
428 /* And now, let's invoke our siblings */
429 return bus_match_run(bus, node->next, m);
430}
431
432static int bus_match_add_compare_value(
433 struct bus_match_node *where,
434 enum bus_match_node_type t,
435 uint8_t value_u8,
436 const char *value_str,
437 struct bus_match_node **ret) {
438
439 struct bus_match_node *c = NULL((void*)0), *n = NULL((void*)0);
440 int r;
441
442 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/libsystemd/sd-bus/bus-match.c"
, 442, __PRETTY_FUNCTION__); } while (0)
;
443 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){BUS_MATCH_ROOT, BUS_MATCH_VALUE})/sizeof(int
)]; switch(where->type) { case BUS_MATCH_ROOT: case BUS_MATCH_VALUE
: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)"
), "../src/libsystemd/sd-bus/bus-match.c", 443, __PRETTY_FUNCTION__
); } while (0)
;
444 assert(BUS_MATCH_IS_COMPARE(t))do { if ((__builtin_expect(!!(!(BUS_MATCH_IS_COMPARE(t))),0))
) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("BUS_MATCH_IS_COMPARE(t)"
), "../src/libsystemd/sd-bus/bus-match.c", 444, __PRETTY_FUNCTION__
); } while (0)
;
445 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-bus/bus-match.c"
, 445, __PRETTY_FUNCTION__); } while (0)
;
446
447 for (c = where->child; c && c->type != t; c = c->next)
448 ;
449
450 if (c) {
451 /* Comparison node already exists? Then let's see if
452 * the value node exists too. */
453
454 if (t == BUS_MATCH_MESSAGE_TYPE)
455 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)((void *) ((uintptr_t) (value_u8))));
456 else if (BUS_MATCH_CAN_HASH(t))
457 n = hashmap_get(c->compare.children, value_str);
458 else {
459 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
460 ;
461 }
462
463 if (n) {
464 *ret = n;
465 return 0;
466 }
467 } else {
468 /* Comparison node, doesn't exist yet? Then let's
469 * create it. */
470
471 c = new0(struct bus_match_node, 1)((struct bus_match_node*) calloc((1), sizeof(struct bus_match_node
)))
;
472 if (!c) {
473 r = -ENOMEM12;
474 goto fail;
475 }
476
477 c->type = t;
478 c->parent = where;
479 c->next = where->child;
480 if (c->next)
481 c->next->prev = c;
482 where->child = c;
483
484 if (t == BUS_MATCH_MESSAGE_TYPE) {
485 c->compare.children = hashmap_new(NULL)internal_hashmap_new(((void*)0) );
486 if (!c->compare.children) {
487 r = -ENOMEM12;
488 goto fail;
489 }
490 } else if (BUS_MATCH_CAN_HASH(t)) {
491 c->compare.children = hashmap_new(&string_hash_ops)internal_hashmap_new(&string_hash_ops );
492 if (!c->compare.children) {
493 r = -ENOMEM12;
494 goto fail;
495 }
496 }
497 }
498
499 n = new0(struct bus_match_node, 1)((struct bus_match_node*) calloc((1), sizeof(struct bus_match_node
)))
;
500 if (!n) {
501 r = -ENOMEM12;
502 goto fail;
503 }
504
505 n->type = BUS_MATCH_VALUE;
506 n->value.u8 = value_u8;
507 if (value_str) {
508 n->value.str = strdup(value_str);
509 if (!n->value.str) {
510 r = -ENOMEM12;
511 goto fail;
512 }
513 }
514
515 n->parent = c;
516 if (c->compare.children) {
517
518 if (t == BUS_MATCH_MESSAGE_TYPE)
519 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8)((void *) ((uintptr_t) (value_u8))), n);
520 else
521 r = hashmap_put(c->compare.children, n->value.str, n);
522
523 if (r < 0)
524 goto fail;
525 } else {
526 n->next = c->child;
527 if (n->next)
528 n->next->prev = n;
529 c->child = n;
530 }
531
532 *ret = n;
533 return 1;
534
535fail:
536 if (c)
537 bus_match_node_maybe_free(c);
538
539 if (n) {
540 free(n->value.str);
541 free(n);
542 }
543
544 return r;
545}
546
547static int bus_match_find_compare_value(
548 struct bus_match_node *where,
549 enum bus_match_node_type t,
550 uint8_t value_u8,
551 const char *value_str,
552 struct bus_match_node **ret) {
553
554 struct bus_match_node *c, *n;
555
556 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/libsystemd/sd-bus/bus-match.c"
, 556, __PRETTY_FUNCTION__); } while (0)
;
557 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){BUS_MATCH_ROOT, BUS_MATCH_VALUE})/sizeof(int
)]; switch(where->type) { case BUS_MATCH_ROOT: case BUS_MATCH_VALUE
: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)"
), "../src/libsystemd/sd-bus/bus-match.c", 557, __PRETTY_FUNCTION__
); } while (0)
;
558 assert(BUS_MATCH_IS_COMPARE(t))do { if ((__builtin_expect(!!(!(BUS_MATCH_IS_COMPARE(t))),0))
) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("BUS_MATCH_IS_COMPARE(t)"
), "../src/libsystemd/sd-bus/bus-match.c", 558, __PRETTY_FUNCTION__
); } while (0)
;
559 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-bus/bus-match.c"
, 559, __PRETTY_FUNCTION__); } while (0)
;
560
561 for (c = where->child; c && c->type != t; c = c->next)
562 ;
563
564 if (!c)
565 return 0;
566
567 if (t == BUS_MATCH_MESSAGE_TYPE)
568 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)((void *) ((uintptr_t) (value_u8))));
569 else if (BUS_MATCH_CAN_HASH(t))
570 n = hashmap_get(c->compare.children, value_str);
571 else {
572 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
573 ;
574 }
575
576 if (n) {
577 *ret = n;
578 return 1;
579 }
580
581 return 0;
582}
583
584static int bus_match_add_leaf(
585 struct bus_match_node *where,
586 struct match_callback *callback) {
587
588 struct bus_match_node *n;
589
590 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/libsystemd/sd-bus/bus-match.c"
, 590, __PRETTY_FUNCTION__); } while (0)
;
591 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){BUS_MATCH_ROOT, BUS_MATCH_VALUE})/sizeof(int
)]; switch(where->type) { case BUS_MATCH_ROOT: case BUS_MATCH_VALUE
: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)"
), "../src/libsystemd/sd-bus/bus-match.c", 591, __PRETTY_FUNCTION__
); } while (0)
;
592 assert(callback)do { if ((__builtin_expect(!!(!(callback)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("callback"), "../src/libsystemd/sd-bus/bus-match.c"
, 592, __PRETTY_FUNCTION__); } while (0)
;
593
594 n = new0(struct bus_match_node, 1)((struct bus_match_node*) calloc((1), sizeof(struct bus_match_node
)))
;
595 if (!n)
596 return -ENOMEM12;
597
598 n->type = BUS_MATCH_LEAF;
599 n->parent = where;
600 n->next = where->child;
601 if (n->next)
602 n->next->prev = n;
603
604 n->leaf.callback = callback;
605 callback->match_node = n;
606
607 where->child = n;
608
609 return 1;
610}
611
612static int bus_match_find_leaf(
613 struct bus_match_node *where,
614 sd_bus_message_handler_t callback,
615 void *userdata,
616 struct bus_match_node **ret) {
617
618 struct bus_match_node *c;
619
620 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/libsystemd/sd-bus/bus-match.c"
, 620, __PRETTY_FUNCTION__); } while (0)
;
621 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){BUS_MATCH_ROOT, BUS_MATCH_VALUE})/sizeof(int
)]; switch(where->type) { case BUS_MATCH_ROOT: case BUS_MATCH_VALUE
: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)"
), "../src/libsystemd/sd-bus/bus-match.c", 621, __PRETTY_FUNCTION__
); } while (0)
;
622 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-bus/bus-match.c"
, 622, __PRETTY_FUNCTION__); } while (0)
;
623
624 for (c = where->child; c; c = c->next) {
625 sd_bus_slot *s;
626
627 s = container_of(c->leaf.callback, sd_bus_slot, match_callback)__extension__ ({ const typeof( ((sd_bus_slot*)0)->match_callback
) *__unique_prefix_A17 = ((c->leaf.callback)); (sd_bus_slot
*)( (char *)__unique_prefix_A17 - __builtin_offsetof(sd_bus_slot
, match_callback) ); })
;
628
629 if (c->type == BUS_MATCH_LEAF &&
630 c->leaf.callback->callback == callback &&
631 s->userdata == userdata) {
632 *ret = c;
633 return 1;
634 }
635 }
636
637 return 0;
638}
639
640enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
641 assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("k"), "../src/libsystemd/sd-bus/bus-match.c"
, 641, __PRETTY_FUNCTION__); } while (0)
;
642
643 if (n == 4 && startswith(k, "type"))
644 return BUS_MATCH_MESSAGE_TYPE;
645 if (n == 6 && startswith(k, "sender"))
646 return BUS_MATCH_SENDER;
647 if (n == 11 && startswith(k, "destination"))
648 return BUS_MATCH_DESTINATION;
649 if (n == 9 && startswith(k, "interface"))
650 return BUS_MATCH_INTERFACE;
651 if (n == 6 && startswith(k, "member"))
652 return BUS_MATCH_MEMBER;
653 if (n == 4 && startswith(k, "path"))
654 return BUS_MATCH_PATH;
655 if (n == 14 && startswith(k, "path_namespace"))
656 return BUS_MATCH_PATH_NAMESPACE;
657
658 if (n == 4 && startswith(k, "arg")) {
659 int j;
660
661 j = undecchar(k[3]);
662 if (j < 0)
663 return -EINVAL22;
664
665 return BUS_MATCH_ARG + j;
666 }
667
668 if (n == 5 && startswith(k, "arg")) {
669 int a, b;
670 enum bus_match_node_type t;
671
672 a = undecchar(k[3]);
673 b = undecchar(k[4]);
674 if (a <= 0 || b < 0)
675 return -EINVAL22;
676
677 t = BUS_MATCH_ARG + a * 10 + b;
678 if (t > BUS_MATCH_ARG_LAST)
679 return -EINVAL22;
680
681 return t;
682 }
683
684 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
685 int j;
686
687 j = undecchar(k[3]);
688 if (j < 0)
689 return -EINVAL22;
690
691 return BUS_MATCH_ARG_PATH + j;
692 }
693
694 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
695 enum bus_match_node_type t;
696 int a, b;
697
698 a = undecchar(k[3]);
699 b = undecchar(k[4]);
700 if (a <= 0 || b < 0)
701 return -EINVAL22;
702
703 t = BUS_MATCH_ARG_PATH + a * 10 + b;
704 if (t > BUS_MATCH_ARG_PATH_LAST)
705 return -EINVAL22;
706
707 return t;
708 }
709
710 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
711 int j;
712
713 j = undecchar(k[3]);
714 if (j < 0)
715 return -EINVAL22;
716
717 return BUS_MATCH_ARG_NAMESPACE + j;
718 }
719
720 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
721 enum bus_match_node_type t;
722 int a, b;
723
724 a = undecchar(k[3]);
725 b = undecchar(k[4]);
726 if (a <= 0 || b < 0)
727 return -EINVAL22;
728
729 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
730 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
731 return -EINVAL22;
732
733 return t;
734 }
735
736 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
737 int j;
738
739 j = undecchar(k[3]);
740 if (j < 0)
741 return -EINVAL22;
742
743 return BUS_MATCH_ARG_HAS + j;
744 }
745
746 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
747 enum bus_match_node_type t;
748 int a, b;
749
750 a = undecchar(k[3]);
751 b = undecchar(k[4]);
752 if (a <= 0 || b < 0)
753 return -EINVAL22;
754
755 t = BUS_MATCH_ARG_HAS + a * 10 + b;
756 if (t > BUS_MATCH_ARG_HAS_LAST)
757 return -EINVAL22;
758
759 return t;
760 }
761
762 return -EINVAL22;
763}
764
765static int match_component_compare(const void *a, const void *b) {
766 const struct bus_match_component *x = a, *y = b;
767
768 if (x->type < y->type)
769 return -1;
770 if (x->type > y->type)
771 return 1;
772
773 return 0;
774}
775
776void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
777 unsigned i;
778
779 for (i = 0; i < n_components; i++)
780 free(components[i].value_str);
781
782 free(components);
783}
784
785int bus_match_parse(
786 const char *match,
787 struct bus_match_component **_components,
788 unsigned *_n_components) {
789
790 const char *p = match;
791 struct bus_match_component *components = NULL((void*)0);
792 size_t components_allocated = 0;
793 unsigned n_components = 0, i;
794 _cleanup_free___attribute__((cleanup(freep))) char *value = NULL((void*)0);
795 int r;
796
797 assert(match)do { if ((__builtin_expect(!!(!(match)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("match"), "../src/libsystemd/sd-bus/bus-match.c"
, 797, __PRETTY_FUNCTION__); } while (0)
;
798 assert(_components)do { if ((__builtin_expect(!!(!(_components)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_components"), "../src/libsystemd/sd-bus/bus-match.c"
, 798, __PRETTY_FUNCTION__); } while (0)
;
799 assert(_n_components)do { if ((__builtin_expect(!!(!(_n_components)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_n_components"), "../src/libsystemd/sd-bus/bus-match.c"
, 799, __PRETTY_FUNCTION__); } while (0)
;
800
801 while (*p != 0) {
802 const char *eq, *q;
803 enum bus_match_node_type t;
804 unsigned j = 0;
805 size_t value_allocated = 0;
806 bool_Bool escaped = false0, quoted;
807 uint8_t u;
808
809 /* Avahi's match rules appear to include whitespace, skip over it */
810 p += strspn(p, " ");
811
812 eq = strchr(p, '=');
813 if (!eq)
814 return -EINVAL22;
815
816 t = bus_match_node_type_from_string(p, eq - p);
817 if (t < 0)
818 return -EINVAL22;
819
820 quoted = eq[1] == '\'';
821
822 for (q = eq + 1 + quoted;; q++) {
823
824 if (*q == 0) {
825
826 if (quoted) {
827 r = -EINVAL22;
828 goto fail;
829 } else {
830 if (value)
831 value[j] = 0;
832 break;
833 }
834 }
835
836 if (!escaped) {
837 if (*q == '\\') {
838 escaped = true1;
839 continue;
840 }
841
842 if (quoted) {
843 if (*q == '\'') {
844 if (value)
845 value[j] = 0;
846 break;
847 }
848 } else {
849 if (*q == ',') {
850 if (value)
851 value[j] = 0;
852
853 break;
854 }
855 }
856 }
857
858 if (!GREEDY_REALLOC(value, value_allocated, j + 2)greedy_realloc((void**) &(value), &(value_allocated),
(j + 2), sizeof((value)[0]))
) {
859 r = -ENOMEM12;
860 goto fail;
861 }
862
863 value[j++] = *q;
864 escaped = false0;
865 }
866
867 if (!value) {
868 value = strdup("");
869 if (!value) {
870 r = -ENOMEM12;
871 goto fail;
872 }
873 }
874
875 if (t == BUS_MATCH_MESSAGE_TYPE) {
876 r = bus_message_type_from_string(value, &u);
877 if (r < 0)
878 goto fail;
879
880 value = mfree(value);
881 } else
882 u = 0;
883
884 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)greedy_realloc((void**) &(components), &(components_allocated
), (n_components + 1), sizeof((components)[0]))
) {
885 r = -ENOMEM12;
886 goto fail;
887 }
888
889 components[n_components].type = t;
890 components[n_components].value_str = TAKE_PTR(value)({ typeof(value) _ptr_ = (value); (value) = ((void*)0); _ptr_
; })
;
891 components[n_components].value_u8 = u;
892 n_components++;
893
894 if (q[quoted] == 0)
895 break;
896
897 if (q[quoted] != ',') {
898 r = -EINVAL22;
899 goto fail;
900 }
901
902 p = q + 1 + quoted;
903 }
904
905 /* Order the whole thing, so that we always generate the same tree */
906 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
907
908 /* Check for duplicates */
909 for (i = 0; i+1 < n_components; i++)
910 if (components[i].type == components[i+1].type) {
911 r = -EINVAL22;
912 goto fail;
913 }
914
915 *_components = components;
916 *_n_components = n_components;
917
918 return 0;
919
920fail:
921 bus_match_parse_free(components, n_components);
922 return r;
923}
924
925char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
926 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
927 char *buffer = NULL((void*)0);
928 size_t size = 0;
929 unsigned i;
930 int r;
931
932 if (n_components <= 0)
933 return strdup("");
934
935 assert(components)do { if ((__builtin_expect(!!(!(components)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("components"), "../src/libsystemd/sd-bus/bus-match.c"
, 935, __PRETTY_FUNCTION__); } while (0)
;
936
937 f = open_memstream(&buffer, &size);
938 if (!f)
939 return NULL((void*)0);
940
941 __fsetlocking(f, FSETLOCKING_BYCALLERFSETLOCKING_BYCALLER);
942
943 for (i = 0; i < n_components; i++) {
944 char buf[32];
945
946 if (i != 0)
947 fputc(',', f);
948
949 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
950 fputc('=', f);
951 fputc('\'', f);
952
953 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
954 fputs(bus_message_type_to_string(components[i].value_u8), f);
955 else
956 fputs(components[i].value_str, f);
957
958 fputc('\'', f);
959 }
960
961 r = fflush_and_check(f);
962 if (r < 0)
963 return NULL((void*)0);
964
965 return buffer;
966}
967
968int bus_match_add(
969 struct bus_match_node *root,
970 struct bus_match_component *components,
971 unsigned n_components,
972 struct match_callback *callback) {
973
974 unsigned i;
975 struct bus_match_node *n;
976 int r;
977
978 assert(root)do { if ((__builtin_expect(!!(!(root)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("root"), "../src/libsystemd/sd-bus/bus-match.c"
, 978, __PRETTY_FUNCTION__); } while (0)
;
979 assert(callback)do { if ((__builtin_expect(!!(!(callback)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("callback"), "../src/libsystemd/sd-bus/bus-match.c"
, 979, __PRETTY_FUNCTION__); } while (0)
;
980
981 n = root;
982 for (i = 0; i < n_components; i++) {
983 r = bus_match_add_compare_value(
984 n, components[i].type,
985 components[i].value_u8, components[i].value_str, &n);
986 if (r < 0)
987 return r;
988 }
989
990 return bus_match_add_leaf(n, callback);
991}
992
993int bus_match_remove(
994 struct bus_match_node *root,
995 struct match_callback *callback) {
996
997 struct bus_match_node *node, *pp;
998
999 assert(root)do { if ((__builtin_expect(!!(!(root)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("root"), "../src/libsystemd/sd-bus/bus-match.c"
, 999, __PRETTY_FUNCTION__); } while (0)
;
1000 assert(callback)do { if ((__builtin_expect(!!(!(callback)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("callback"), "../src/libsystemd/sd-bus/bus-match.c"
, 1000, __PRETTY_FUNCTION__); } while (0)
;
1001
1002 node = callback->match_node;
1003 if (!node)
1004 return 0;
1005
1006 assert(node->type == BUS_MATCH_LEAF)do { if ((__builtin_expect(!!(!(node->type == BUS_MATCH_LEAF
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("node->type == BUS_MATCH_LEAF"
), "../src/libsystemd/sd-bus/bus-match.c", 1006, __PRETTY_FUNCTION__
); } while (0)
;
1007
1008 callback->match_node = NULL((void*)0);
1009
1010 /* Free the leaf */
1011 pp = node->parent;
1012 bus_match_node_free(node);
1013
1014 /* Prune the tree above */
1015 while (pp) {
1016 node = pp;
1017 pp = node->parent;
1018
1019 if (!bus_match_node_maybe_free(node))
1020 break;
1021 }
1022
1023 return 1;
1024}
1025
1026int bus_match_find(
1027 struct bus_match_node *root,
1028 struct bus_match_component *components,
1029 unsigned n_components,
1030 sd_bus_message_handler_t callback,
1031 void *userdata,
1032 struct match_callback **ret) {
1033
1034 struct bus_match_node *n, **gc;
1035 unsigned i;
1036 int r;
1037
1038 assert(root)do { if ((__builtin_expect(!!(!(root)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("root"), "../src/libsystemd/sd-bus/bus-match.c"
, 1038, __PRETTY_FUNCTION__); } while (0)
;
1039 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-bus/bus-match.c"
, 1039, __PRETTY_FUNCTION__); } while (0)
;
1040
1041 gc = newa(struct bus_match_node*, n_components)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(struct bus_match_node*), n_components))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(struct bus_match_node*), n_components)"
), "../src/libsystemd/sd-bus/bus-match.c", 1041, __PRETTY_FUNCTION__
); } while (0); (struct bus_match_node**) __builtin_alloca (sizeof
(struct bus_match_node*)*(n_components)); })
;
1042
1043 n = root;
1044 for (i = 0; i < n_components; i++) {
1045 r = bus_match_find_compare_value(
1046 n, components[i].type,
1047 components[i].value_u8, components[i].value_str,
1048 &n);
1049 if (r <= 0)
1050 return r;
1051
1052 gc[i] = n;
1053 }
1054
1055 r = bus_match_find_leaf(n, callback, userdata, &n);
1056 if (r <= 0)
1057 return r;
1058
1059 *ret = n->leaf.callback;
1060 return 1;
1061}
1062
1063void bus_match_free(struct bus_match_node *node) {
1064 struct bus_match_node *c;
1065
1066 if (!node
5.1
'node' is non-null
)
1
Assuming 'node' is non-null
2
Taking false branch
6
Taking false branch
1067 return;
1068
1069 if (BUS_MATCH_CAN_HASH(node->type)) {
3
Taking false branch
7
Taking false branch
1070 Iterator i;
1071
1072 HASHMAP_FOREACH(c, node->compare.children, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((node->compare.children
), &(i), (void**)&(c), ((void*)0)); )
1073 bus_match_free(c);
1074
1075 assert(hashmap_isempty(node->compare.children))do { if ((__builtin_expect(!!(!(hashmap_isempty(node->compare
.children))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"hashmap_isempty(node->compare.children)"), "../src/libsystemd/sd-bus/bus-match.c"
, 1075, __PRETTY_FUNCTION__); } while (0)
;
1076 }
1077
1078 while ((c = node->child))
4
Loop condition is true. Entering loop body
8
Loop condition is false. Execution continues on line 1081
31
Loop condition is true. Entering loop body
1079 bus_match_free(c);
5
Calling 'bus_match_free'
30
Returning; memory was released via 1st parameter
32
Use of memory after it is freed
1080
1081 if (node->type != BUS_MATCH_ROOT)
9
Assuming field 'type' is not equal to BUS_MATCH_ROOT
10
Taking true branch
1082 bus_match_node_free(node);
11
Calling 'bus_match_node_free'
29
Returning; memory was released via 1st parameter
1083}
1084
1085const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1086 switch (t) {
1087
1088 case BUS_MATCH_ROOT:
1089 return "root";
1090
1091 case BUS_MATCH_VALUE:
1092 return "value";
1093
1094 case BUS_MATCH_LEAF:
1095 return "leaf";
1096
1097 case BUS_MATCH_MESSAGE_TYPE:
1098 return "type";
1099
1100 case BUS_MATCH_SENDER:
1101 return "sender";
1102
1103 case BUS_MATCH_DESTINATION:
1104 return "destination";
1105
1106 case BUS_MATCH_INTERFACE:
1107 return "interface";
1108
1109 case BUS_MATCH_MEMBER:
1110 return "member";
1111
1112 case BUS_MATCH_PATH:
1113 return "path";
1114
1115 case BUS_MATCH_PATH_NAMESPACE:
1116 return "path_namespace";
1117
1118 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1119 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1120 return buf;
1121
1122 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1123 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1124 return buf;
1125
1126 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1127 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1128 return buf;
1129
1130 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1131 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1132 return buf;
1133
1134 default:
1135 return NULL((void*)0);
1136 }
1137}
1138
1139void bus_match_dump(struct bus_match_node *node, unsigned level) {
1140 struct bus_match_node *c;
1141 _cleanup_free___attribute__((cleanup(freep))) char *pfx = NULL((void*)0);
1142 char buf[32];
1143
1144 if (!node)
1145 return;
1146
1147 pfx = strrep(" ", level);
1148 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1149
1150 if (node->type == BUS_MATCH_VALUE) {
1151 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1152 printf(" <%u>\n", node->value.u8);
1153 else
1154 printf(" <%s>\n", node->value.str);
1155 } else if (node->type == BUS_MATCH_ROOT)
1156 puts(" root");
1157 else if (node->type == BUS_MATCH_LEAF)
1158 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)__extension__ ({ const typeof( ((sd_bus_slot*)0)->match_callback
) *__unique_prefix_A18 = ((node->leaf.callback)); (sd_bus_slot
*)( (char *)__unique_prefix_A18 - __builtin_offsetof(sd_bus_slot
, match_callback) ); })
->userdata);
1159 else
1160 putchar('\n');
1161
1162 if (BUS_MATCH_CAN_HASH(node->type)) {
1163 Iterator i;
1164
1165 HASHMAP_FOREACH(c, node->compare.children, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((node->compare.children
), &(i), (void**)&(c), ((void*)0)); )
1166 bus_match_dump(c, level + 1);
1167 }
1168
1169 for (c = node->child; c; c = c->next)
1170 bus_match_dump(c, level + 1);
1171}
1172
1173enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1174 bool_Bool found_driver = false0;
1175 unsigned i;
1176
1177 if (n_components <= 0)
1178 return BUS_MATCH_GENERIC;
1179
1180 assert(components)do { if ((__builtin_expect(!!(!(components)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("components"), "../src/libsystemd/sd-bus/bus-match.c"
, 1180, __PRETTY_FUNCTION__); } while (0)
;
1181
1182 /* Checks whether the specified match can only match the
1183 * pseudo-service for local messages, which we detect by
1184 * sender, interface or path. If a match is not restricted to
1185 * local messages, then we check if it only matches on the
1186 * driver. */
1187
1188 for (i = 0; i < n_components; i++) {
1189 const struct bus_match_component *c = components + i;
1190
1191 if (c->type == BUS_MATCH_SENDER) {
1192 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1193 return BUS_MATCH_LOCAL;
1194
1195 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1196 found_driver = true1;
1197 }
1198
1199 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1200 return BUS_MATCH_LOCAL;
1201
1202 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1203 return BUS_MATCH_LOCAL;
1204 }
1205
1206 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
1207
1208}