Bug Summary

File:build-scan/../src/libsystemd/sd-bus/bus-track.c
Warning:line 232, column 25
Potential leak of memory pointed to by 'n'

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-track.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-track.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3***/
4
5#include "sd-bus.h"
6
7#include "alloc-util.h"
8#include "bus-internal.h"
9#include "bus-track.h"
10#include "bus-util.h"
11
12struct track_item {
13 unsigned n_ref;
14 char *name;
15 sd_bus_slot *slot;
16};
17
18struct sd_bus_track {
19 unsigned n_ref;
20 unsigned n_adding; /* are we in the process of adding a new name? */
21 sd_bus *bus;
22 sd_bus_track_handler_t handler;
23 void *userdata;
24 Hashmap *names;
25 LIST_FIELDS(sd_bus_track, queue)sd_bus_track *queue_next, *queue_prev;
26 Iterator iterator;
27 bool_Bool in_list:1; /* In bus->tracks? */
28 bool_Bool in_queue:1; /* In bus->track_queue? */
29 bool_Bool modified:1;
30 bool_Bool recursive:1;
31 sd_bus_destroy_t destroy_callback;
32
33 LIST_FIELDS(sd_bus_track, tracks)sd_bus_track *tracks_next, *tracks_prev;
34};
35
36#define MATCH_FOR_NAME(name)({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
\
37 strjoina("type='signal'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
38 "sender='org.freedesktop.DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
39 "path='/org/freedesktop/DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
40 "interface='org.freedesktop.DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
41 "member='NameOwnerChanged'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
42 "arg0='", name, "'")({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
43
44static struct track_item* track_item_free(struct track_item *i) {
45
46 if (!i)
47 return NULL((void*)0);
48
49 sd_bus_slot_unref(i->slot);
50 free(i->name);
51 return mfree(i);
52}
53
54DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free)static inline void track_item_freep(struct track_item* *p) { if
(*p) track_item_free(*p); }
;
55
56static void bus_track_add_to_queue(sd_bus_track *track) {
57 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 57, __PRETTY_FUNCTION__); } while (0)
;
58
59 /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of
60 * conditions. */
61
62 /* Already in the queue? */
63 if (track->in_queue)
64 return;
65
66 /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait
67 * until the addition is complete. */
68 if (track->n_adding > 0)
69 return;
70
71 /* still referenced? */
72 if (hashmap_size(track->names) > 0)
73 return;
74
75 /* Nothing to call? */
76 if (!track->handler)
77 return;
78
79 /* Already closed? */
80 if (!track->in_list)
81 return;
82
83 LIST_PREPEND(queue, track->bus->track_queue, track)do { typeof(*(track->bus->track_queue)) **_head = &
(track->bus->track_queue), *_item = (track); do { if ((
__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 83, __PRETTY_FUNCTION__
); } while (0); if ((_item->queue_next = *_head)) _item->
queue_next->queue_prev = _item; _item->queue_prev = ((void
*)0); *_head = _item; } while (0)
;
84 track->in_queue = true1;
85}
86
87static void bus_track_remove_from_queue(sd_bus_track *track) {
88 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 88, __PRETTY_FUNCTION__); } while (0)
;
89
90 if (!track->in_queue)
91 return;
92
93 LIST_REMOVE(queue, track->bus->track_queue, track)do { typeof(*(track->bus->track_queue)) **_head = &
(track->bus->track_queue), *_item = (track); do { if ((
__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 93, __PRETTY_FUNCTION__
); } while (0); if (_item->queue_next) _item->queue_next
->queue_prev = _item->queue_prev; if (_item->queue_prev
) _item->queue_prev->queue_next = _item->queue_next;
else { do { if ((__builtin_expect(!!(!(*_head == _item)),0))
) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/libsystemd/sd-bus/bus-track.c", 93, __PRETTY_FUNCTION__
); } while (0); *_head = _item->queue_next; } _item->queue_next
= _item->queue_prev = ((void*)0); } while (0)
;
94 track->in_queue = false0;
95}
96
97static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) {
98 struct track_item *i;
99
100 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 100, __PRETTY_FUNCTION__); } while (0)
;
101 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c"
, 101, __PRETTY_FUNCTION__); } while (0)
;
102
103 i = hashmap_remove(track->names, name);
104 if (!i)
105 return 0;
106
107 track_item_free(i);
108
109 bus_track_add_to_queue(track);
110
111 track->modified = true1;
112 return 1;
113}
114
115_public___attribute__ ((visibility("default"))) int sd_bus_track_new(
116 sd_bus *bus,
117 sd_bus_track **track,
118 sd_bus_track_handler_t handler,
119 void *userdata) {
120
121 sd_bus_track *t;
122
123 assert_return(bus, -EINVAL)do { if (!(((__builtin_expect(!!(bus),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-track.c"
, 123, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
124 assert_return(bus = bus_resolve(bus), -ENOPKG)do { if (!(((__builtin_expect(!!(bus = bus_resolve(bus)),1)))
? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, (
"bus = bus_resolve(bus)"), "../src/libsystemd/sd-bus/bus-track.c"
, 124, __PRETTY_FUNCTION__), 0))) return (-65); } while (0)
;
125 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 125, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
126
127 if (!bus->bus_client)
128 return -EINVAL22;
129
130 t = new0(sd_bus_track, 1)((sd_bus_track*) calloc((1), sizeof(sd_bus_track)));
131 if (!t)
132 return -ENOMEM12;
133
134 t->n_ref = 1;
135 t->handler = handler;
136 t->userdata = userdata;
137 t->bus = sd_bus_ref(bus);
138
139 LIST_PREPEND(tracks, bus->tracks, t)do { typeof(*(bus->tracks)) **_head = &(bus->tracks
), *_item = (t); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/libsystemd/sd-bus/bus-track.c"
, 139, __PRETTY_FUNCTION__); } while (0); if ((_item->tracks_next
= *_head)) _item->tracks_next->tracks_prev = _item; _item
->tracks_prev = ((void*)0); *_head = _item; } while (0)
;
140 t->in_list = true1;
141
142 bus_track_add_to_queue(t);
143
144 *track = t;
145 return 0;
146}
147
148_public___attribute__ ((visibility("default"))) sd_bus_track* sd_bus_track_ref(sd_bus_track *track) {
149
150 if (!track)
151 return NULL((void*)0);
152
153 assert(track->n_ref > 0)do { if ((__builtin_expect(!!(!(track->n_ref > 0)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("track->n_ref > 0"
), "../src/libsystemd/sd-bus/bus-track.c", 153, __PRETTY_FUNCTION__
); } while (0)
;
154
155 track->n_ref++;
156
157 return track;
158}
159
160_public___attribute__ ((visibility("default"))) sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
161 if (!track)
162 return NULL((void*)0);
163
164 assert(track->n_ref > 0)do { if ((__builtin_expect(!!(!(track->n_ref > 0)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("track->n_ref > 0"
), "../src/libsystemd/sd-bus/bus-track.c", 164, __PRETTY_FUNCTION__
); } while (0)
;
165 track->n_ref--;
166
167 if (track->n_ref > 0)
168 return NULL((void*)0);
169
170 if (track->in_list)
171 LIST_REMOVE(tracks, track->bus->tracks, track)do { typeof(*(track->bus->tracks)) **_head = &(track
->bus->tracks), *_item = (track); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/libsystemd/sd-bus/bus-track.c", 171, __PRETTY_FUNCTION__
); } while (0); if (_item->tracks_next) _item->tracks_next
->tracks_prev = _item->tracks_prev; if (_item->tracks_prev
) _item->tracks_prev->tracks_next = _item->tracks_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/libsystemd/sd-bus/bus-track.c", 171, __PRETTY_FUNCTION__
); } while (0); *_head = _item->tracks_next; } _item->tracks_next
= _item->tracks_prev = ((void*)0); } while (0)
;
172
173 bus_track_remove_from_queue(track);
174 track->names = hashmap_free_with_destructor(track->names, track_item_free)({ ({ void *_item; while ((_item = hashmap_steal_first(track->
names))) track_item_free(_item); }); hashmap_free(track->names
); })
;
175 track->bus = sd_bus_unref(track->bus);
176
177 if (track->destroy_callback)
178 track->destroy_callback(track->userdata);
179
180 return mfree(track);
181}
182
183static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
184 sd_bus_track *track = userdata;
185 const char *name, *old, *new;
186 int r;
187
188 assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("message"), "../src/libsystemd/sd-bus/bus-track.c"
, 188, __PRETTY_FUNCTION__); } while (0)
;
189 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 189, __PRETTY_FUNCTION__); } while (0)
;
190
191 r = sd_bus_message_read(message, "sss", &name, &old, &new);
192 if (r < 0)
193 return 0;
194
195 bus_track_remove_name_fully(track, name);
196 return 0;
197}
198
199_public___attribute__ ((visibility("default"))) int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
200 _cleanup_(track_item_freep)__attribute__((cleanup(track_item_freep))) struct track_item *n = NULL((void*)0);
201 struct track_item *i;
202 const char *match;
203 int r;
204
205 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 205, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
14
'?' condition is true
15
Taking false branch
16
Loop condition is false. Exiting loop
206 assert_return(service_name_is_valid(name), -EINVAL)do { if (!(((__builtin_expect(!!(service_name_is_valid(name))
,1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("service_name_is_valid(name)"), "../src/libsystemd/sd-bus/bus-track.c"
, 206, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
17
Assuming the condition is false
18
'?' condition is true
19
Taking false branch
20
Loop condition is false. Exiting loop
207
208 i = hashmap_get(track->names, name);
209 if (i) {
21
Assuming 'i' is null
22
Taking false branch
210 if (track->recursive) {
211 unsigned k = track->n_ref + 1;
212
213 if (k < track->n_ref) /* Check for overflow */
214 return -EOVERFLOW75;
215
216 track->n_ref = k;
217 }
218
219 bus_track_remove_from_queue(track);
220 return 0;
221 }
222
223 r = hashmap_ensure_allocated(&track->names, &string_hash_ops)internal_hashmap_ensure_allocated(&track->names, &
string_hash_ops )
;
224 if (r < 0)
23
Assuming 'r' is >= 0
24
Taking false branch
225 return r;
226
227 n = new0(struct track_item, 1)((struct track_item*) calloc((1), sizeof(struct track_item)));
25
Memory is allocated
228 if (!n)
26
Assuming 'n' is non-null
27
Taking false branch
229 return -ENOMEM12;
230 n->name = strdup(name);
231 if (!n->name)
28
Assuming field 'name' is null
29
Taking true branch
232 return -ENOMEM12;
30
Potential leak of memory pointed to by 'n'
233
234 /* First, subscribe to this name */
235 match = MATCH_FOR_NAME(name)({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
236
237 bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
238
239 r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, NULL((void*)0), track);
240 if (r < 0) {
241 bus_track_add_to_queue(track);
242 return r;
243 }
244
245 r = hashmap_put(track->names, n->name, n);
246 if (r < 0) {
247 bus_track_add_to_queue(track);
248 return r;
249 }
250
251 /* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */
252 track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */
253 r = sd_bus_get_name_creds(track->bus, name, 0, NULL((void*)0));
254 track->n_adding--;
255 if (r < 0) {
256 hashmap_remove(track->names, name);
257 bus_track_add_to_queue(track);
258 return r;
259 }
260
261 n->n_ref = 1;
262 n = NULL((void*)0);
263
264 bus_track_remove_from_queue(track);
265 track->modified = true1;
266
267 return 1;
268}
269
270_public___attribute__ ((visibility("default"))) int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
271 struct track_item *i;
272
273 assert_return(name, -EINVAL)do { if (!(((__builtin_expect(!!(name),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c"
, 273, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
274
275 if (!track) /* Treat a NULL track object as an empty track object */
276 return 0;
277
278 if (!track->recursive)
279 return bus_track_remove_name_fully(track, name);
280
281 i = hashmap_get(track->names, name);
282 if (!i)
283 return -EUNATCH49;
284 if (i->n_ref <= 0)
285 return -EUNATCH49;
286
287 i->n_ref--;
288
289 if (i->n_ref <= 0)
290 return bus_track_remove_name_fully(track, name);
291
292 return 1;
293}
294
295_public___attribute__ ((visibility("default"))) unsigned sd_bus_track_count(sd_bus_track *track) {
296
297 if (!track) /* Let's consider a NULL object equivalent to an empty object */
298 return 0;
299
300 /* This signature really should have returned an int, so that we can propagate errors. But well, ... Also, note
301 * that this returns the number of names being watched, and multiple references to the same name are not
302 * counted. */
303
304 return hashmap_size(track->names);
305}
306
307_public___attribute__ ((visibility("default"))) const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
308 assert_return(name, NULL)do { if (!(((__builtin_expect(!!(name),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c"
, 308, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while
(0)
;
309
310 if (!track) /* Let's consider a NULL object equivalent to an empty object */
311 return NULL((void*)0);
312
313 return hashmap_get(track->names, (void*) name) ? name : NULL((void*)0);
314}
315
316_public___attribute__ ((visibility("default"))) const char* sd_bus_track_first(sd_bus_track *track) {
317 const char *n = NULL((void*)0);
318
319 if (!track)
320 return NULL((void*)0);
321
322 track->modified = false0;
323 track->iterator = ITERATOR_FIRST((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .next_key = (
(void*)0) })
;
324
325 hashmap_iterate(track->names, &track->iterator, NULL((void*)0), (const void**) &n);
326 return n;
327}
328
329_public___attribute__ ((visibility("default"))) const char* sd_bus_track_next(sd_bus_track *track) {
330 const char *n = NULL((void*)0);
331
332 if (!track)
333 return NULL((void*)0);
334
335 if (track->modified)
336 return NULL((void*)0);
337
338 hashmap_iterate(track->names, &track->iterator, NULL((void*)0), (const void**) &n);
339 return n;
340}
341
342_public___attribute__ ((visibility("default"))) int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
343 const char *sender;
344
345 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 345, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1
Assuming 'track' is non-null
2
'?' condition is true
3
Taking false branch
4
Loop condition is false. Exiting loop
346 assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c"
, 346, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
5
Assuming 'm' is non-null
6
'?' condition is true
7
Taking false branch
8
Loop condition is false. Exiting loop
347
348 if (sd_bus_message_get_bus(m) != track->bus)
9
Assuming the condition is false
10
Taking false branch
349 return -EINVAL22;
350
351 sender = sd_bus_message_get_sender(m);
352 if (!sender)
11
Assuming 'sender' is non-null
12
Taking false branch
353 return -EINVAL22;
354
355 return sd_bus_track_add_name(track, sender);
13
Calling 'sd_bus_track_add_name'
356}
357
358_public___attribute__ ((visibility("default"))) int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) {
359 const char *sender;
360
361 assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c"
, 361, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
362
363 if (!track) /* Treat a NULL track object as an empty track object */
364 return 0;
365
366 if (sd_bus_message_get_bus(m) != track->bus)
367 return -EINVAL22;
368
369 sender = sd_bus_message_get_sender(m);
370 if (!sender)
371 return -EINVAL22;
372
373 return sd_bus_track_remove_name(track, sender);
374}
375
376_public___attribute__ ((visibility("default"))) sd_bus* sd_bus_track_get_bus(sd_bus_track *track) {
377 assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 377, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while
(0)
;
378
379 return track->bus;
380}
381
382void bus_track_dispatch(sd_bus_track *track) {
383 int r;
384
385 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 385, __PRETTY_FUNCTION__); } while (0)
;
386 assert(track->handler)do { if ((__builtin_expect(!!(!(track->handler)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track->handler"), "../src/libsystemd/sd-bus/bus-track.c"
, 386, __PRETTY_FUNCTION__); } while (0)
;
387
388 bus_track_remove_from_queue(track);
389
390 sd_bus_track_ref(track);
391
392 r = track->handler(track, track->userdata);
393 if (r < 0)
394 log_debug_errno(r, "Failed to process track handler: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/libsystemd/sd-bus/bus-track.c", 394, __func__, "Failed to process track handler: %m"
) : -abs(_e); })
;
395 else if (r == 0)
396 bus_track_add_to_queue(track);
397
398 sd_bus_track_unref(track);
399}
400
401void bus_track_close(sd_bus_track *track) {
402 assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 402, __PRETTY_FUNCTION__); } while (0)
;
403
404 /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it
405 * immediately, as we are closing now, but first flush out all names. */
406
407 if (!track->in_list)
408 return; /* We already closed this one, don't close it again. */
409
410 /* Remember that this one is closed now */
411 LIST_REMOVE(tracks, track->bus->tracks, track)do { typeof(*(track->bus->tracks)) **_head = &(track
->bus->tracks), *_item = (track); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/libsystemd/sd-bus/bus-track.c", 411, __PRETTY_FUNCTION__
); } while (0); if (_item->tracks_next) _item->tracks_next
->tracks_prev = _item->tracks_prev; if (_item->tracks_prev
) _item->tracks_prev->tracks_next = _item->tracks_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/libsystemd/sd-bus/bus-track.c", 411, __PRETTY_FUNCTION__
); } while (0); *_head = _item->tracks_next; } _item->tracks_next
= _item->tracks_prev = ((void*)0); } while (0)
;
412 track->in_list = false0;
413
414 /* If there's no name in this one anyway, we don't have to dispatch */
415 if (hashmap_isempty(track->names))
416 return;
417
418 /* Let's flush out all names */
419 hashmap_clear_with_destructor(track->names, track_item_free)({ void *_item; while ((_item = hashmap_steal_first(track->
names))) track_item_free(_item); })
;
420
421 /* Invoke handler */
422 if (track->handler)
423 bus_track_dispatch(track);
424}
425
426_public___attribute__ ((visibility("default"))) void *sd_bus_track_get_userdata(sd_bus_track *track) {
427 assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 427, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while
(0)
;
428
429 return track->userdata;
430}
431
432_public___attribute__ ((visibility("default"))) void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
433 void *ret;
434
435 assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 435, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while
(0)
;
436
437 ret = track->userdata;
438 track->userdata = userdata;
439
440 return ret;
441}
442
443_public___attribute__ ((visibility("default"))) int sd_bus_track_set_destroy_callback(sd_bus_track *track, sd_bus_destroy_t callback) {
444 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 444, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
445
446 track->destroy_callback = callback;
447 return 0;
448}
449
450_public___attribute__ ((visibility("default"))) int sd_bus_track_get_destroy_callback(sd_bus_track *track, sd_bus_destroy_t *ret) {
451 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 451, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
452
453 if (ret)
454 *ret = track->destroy_callback;
455
456 return !!track->destroy_callback;
457}
458
459_public___attribute__ ((visibility("default"))) int sd_bus_track_set_recursive(sd_bus_track *track, int b) {
460 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 460, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
461
462 if (track->recursive == !!b)
463 return 0;
464
465 if (!hashmap_isempty(track->names))
466 return -EBUSY16;
467
468 track->recursive = b;
469 return 0;
470}
471
472_public___attribute__ ((visibility("default"))) int sd_bus_track_get_recursive(sd_bus_track *track) {
473 assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c"
, 473, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
474
475 return track->recursive;
476}
477
478_public___attribute__ ((visibility("default"))) int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m) {
479 const char *sender;
480
481 assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c"
, 481, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
482
483 if (!track) /* Let's consider a NULL object equivalent to an empty object */
484 return 0;
485
486 if (sd_bus_message_get_bus(m) != track->bus)
487 return -EINVAL22;
488
489 sender = sd_bus_message_get_sender(m);
490 if (!sender)
491 return -EINVAL22;
492
493 return sd_bus_track_count_name(track, sender);
494}
495
496_public___attribute__ ((visibility("default"))) int sd_bus_track_count_name(sd_bus_track *track, const char *name) {
497 struct track_item *i;
498
499 assert_return(service_name_is_valid(name), -EINVAL)do { if (!(((__builtin_expect(!!(service_name_is_valid(name))
,1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("service_name_is_valid(name)"), "../src/libsystemd/sd-bus/bus-track.c"
, 499, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
500
501 if (!track) /* Let's consider a NULL object equivalent to an empty object */
502 return 0;
503
504 i = hashmap_get(track->names, name);
505 if (!i)
506 return 0;
507
508 return i->n_ref;
509}