Bug Summary

File:build-scan/../src/import/curl-util.c
Warning:line 243, column 25
Potential leak of memory pointed to by 'g'

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 curl-util.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 static -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 systemd-pull.p -I . -I .. -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 -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 hidden -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/import/curl-util.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "alloc-util.h"
4#include "curl-util.h"
5#include "fd-util.h"
6#include "locale-util.h"
7#include "string-util.h"
8
9static void curl_glue_check_finished(CurlGlue *g) {
10 CURLMsg *msg;
11 int k = 0;
12
13 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 13, __PRETTY_FUNCTION__
); } while (0)
;
14
15 msg = curl_multi_info_read(g->curl, &k);
16 if (!msg)
17 return;
18
19 if (msg->msg != CURLMSG_DONE)
20 return;
21
22 if (g->on_finished)
23 g->on_finished(g, msg->easy_handle, msg->data.result);
24}
25
26static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
27 CurlGlue *g = userdata;
28 int action, k = 0, translated_fd;
29
30 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/import/curl-util.c", 30, __PRETTY_FUNCTION__
); } while (0)
;
31 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 31, __PRETTY_FUNCTION__
); } while (0)
;
32
33 translated_fd = PTR_TO_FD(hashmap_get(g->translate_fds, FD_TO_PTR(fd)))(((int) ((intptr_t) (hashmap_get(g->translate_fds, ((void *
) ((intptr_t) ((fd)+1)))))))-1)
;
34
35 if (FLAGS_SET(revents, EPOLLIN | EPOLLOUT)(((revents) & (EPOLLIN | EPOLLOUT)) == (EPOLLIN | EPOLLOUT
))
)
36 action = CURL_POLL_INOUT3;
37 else if (revents & EPOLLINEPOLLIN)
38 action = CURL_POLL_IN1;
39 else if (revents & EPOLLOUTEPOLLOUT)
40 action = CURL_POLL_OUT2;
41 else
42 action = 0;
43
44 if (curl_multi_socket_action(g->curl, translated_fd, action, &k) < 0) {
45 log_debug("Failed to propagate IO event.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/import/curl-util.c", 45, __func__, "Failed to propagate IO event."
) : -abs(_e); })
;
46 return -EINVAL22;
47 }
48
49 curl_glue_check_finished(g);
50 return 0;
51}
52
53static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) {
54 sd_event_source *io;
55 CurlGlue *g = userdata;
56 uint32_t events = 0;
57 int r;
58
59 assert(curl)do { if ((__builtin_expect(!!(!(curl)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("curl"), "../src/import/curl-util.c", 59
, __PRETTY_FUNCTION__); } while (0)
;
60 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 60, __PRETTY_FUNCTION__
); } while (0)
;
61
62 io = hashmap_get(g->ios, FD_TO_PTR(s)((void *) ((intptr_t) ((s)+1))));
63
64 if (action == CURL_POLL_REMOVE4) {
65 if (io) {
66 int fd;
67
68 fd = sd_event_source_get_io_fd(io);
69 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/import/curl-util.c"
, 69, __PRETTY_FUNCTION__); } while (0)
;
70
71 sd_event_source_set_enabled(io, SD_EVENT_OFF);
72 sd_event_source_unref(io);
73
74 hashmap_remove(g->ios, FD_TO_PTR(s)((void *) ((intptr_t) ((s)+1))));
75 hashmap_remove(g->translate_fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))));
76
77 safe_close(fd);
78 }
79
80 return 0;
81 }
82
83 r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops)internal_hashmap_ensure_allocated(&g->ios, &trivial_hash_ops
)
;
84 if (r < 0) {
85 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/curl-util.c"
, 85, __func__)
;
86 return -1;
87 }
88
89 r = hashmap_ensure_allocated(&g->translate_fds, &trivial_hash_ops)internal_hashmap_ensure_allocated(&g->translate_fds, &
trivial_hash_ops )
;
90 if (r < 0) {
91 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/curl-util.c"
, 91, __func__)
;
92 return -1;
93 }
94
95 if (action == CURL_POLL_IN1)
96 events = EPOLLINEPOLLIN;
97 else if (action == CURL_POLL_OUT2)
98 events = EPOLLOUTEPOLLOUT;
99 else if (action == CURL_POLL_INOUT3)
100 events = EPOLLINEPOLLIN|EPOLLOUTEPOLLOUT;
101
102 if (io) {
103 if (sd_event_source_set_io_events(io, events) < 0)
104 return -1;
105
106 if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0)
107 return -1;
108 } else {
109 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
110
111 /* When curl needs to remove an fd from us it closes
112 * the fd first, and only then calls into us. This is
113 * nasty, since we cannot pass the fd on to epoll()
114 * anymore. Hence, duplicate the fds here, and keep a
115 * copy for epoll which we control after use. */
116
117 fd = fcntl(s, F_DUPFD_CLOEXEC1030, 3);
118 if (fd < 0)
119 return -1;
120
121 if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
122 return -1;
123
124 (void) sd_event_source_set_description(io, "curl-io");
125
126 r = hashmap_put(g->ios, FD_TO_PTR(s)((void *) ((intptr_t) ((s)+1))), io);
127 if (r < 0) {
128 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/curl-util.c"
, 128, __func__)
;
129 sd_event_source_unref(io);
130 return -1;
131 }
132
133 r = hashmap_put(g->translate_fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))), FD_TO_PTR(s)((void *) ((intptr_t) ((s)+1))));
134 if (r < 0) {
135 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/curl-util.c"
, 135, __func__)
;
136 hashmap_remove(g->ios, FD_TO_PTR(s)((void *) ((intptr_t) ((s)+1))));
137 sd_event_source_unref(io);
138 return -1;
139 }
140
141 fd = -1;
142 }
143
144 return 0;
145}
146
147static int curl_glue_on_timer(sd_event_source *s, uint64_t usec, void *userdata) {
148 CurlGlue *g = userdata;
149 int k = 0;
150
151 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/import/curl-util.c", 151, __PRETTY_FUNCTION__
); } while (0)
;
152 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 152, __PRETTY_FUNCTION__
); } while (0)
;
153
154 if (curl_multi_socket_action(g->curl, CURL_SOCKET_TIMEOUT-1, 0, &k) != CURLM_OK) {
155 log_debug("Failed to propagate timeout.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/import/curl-util.c", 155, __func__, "Failed to propagate timeout."
) : -abs(_e); })
;
156 return -EINVAL22;
157 }
158
159 curl_glue_check_finished(g);
160 return 0;
161}
162
163static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata) {
164 CurlGlue *g = userdata;
165 usec_t usec;
166
167 assert(curl)do { if ((__builtin_expect(!!(!(curl)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("curl"), "../src/import/curl-util.c", 167
, __PRETTY_FUNCTION__); } while (0)
;
168 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 168, __PRETTY_FUNCTION__
); } while (0)
;
169
170 if (timeout_ms < 0) {
171 if (g->timer) {
172 if (sd_event_source_set_enabled(g->timer, SD_EVENT_OFF) < 0)
173 return -1;
174 }
175
176 return 0;
177 }
178
179 usec = now(clock_boottime_or_monotonic()) + (usec_t) timeout_ms * USEC_PER_MSEC((usec_t) 1000ULL) + USEC_PER_MSEC((usec_t) 1000ULL) - 1;
180
181 if (g->timer) {
182 if (sd_event_source_set_time(g->timer, usec) < 0)
183 return -1;
184
185 if (sd_event_source_set_enabled(g->timer, SD_EVENT_ONESHOT) < 0)
186 return -1;
187 } else {
188 if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
189 return -1;
190
191 (void) sd_event_source_set_description(g->timer, "curl-timer");
192 }
193
194 return 0;
195}
196
197CurlGlue *curl_glue_unref(CurlGlue *g) {
198 sd_event_source *io;
199
200 if (!g)
201 return NULL((void*)0);
202
203 if (g->curl)
204 curl_multi_cleanup(g->curl);
205
206 while ((io = hashmap_steal_first(g->ios))) {
207 int fd;
208
209 fd = sd_event_source_get_io_fd(io);
210 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/import/curl-util.c"
, 210, __PRETTY_FUNCTION__); } while (0)
;
211
212 hashmap_remove(g->translate_fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))));
213
214 safe_close(fd);
215 sd_event_source_unref(io);
216 }
217
218 hashmap_free(g->ios);
219
220 sd_event_source_unref(g->timer);
221 sd_event_unref(g->event);
222 return mfree(g);
223}
224
225int curl_glue_new(CurlGlue **glue, sd_event *event) {
226 _cleanup_(curl_glue_unrefp)__attribute__((cleanup(curl_glue_unrefp))) CurlGlue *g = NULL((void*)0);
227 int r;
228
229 g = new0(CurlGlue, 1)((CurlGlue*) calloc((1), sizeof(CurlGlue)));
1
Memory is allocated
230 if (!g)
2
Assuming 'g' is non-null
3
Taking false branch
231 return -ENOMEM12;
232
233 if (event)
4
Assuming 'event' is non-null
5
Taking true branch
234 g->event = sd_event_ref(event);
235 else {
236 r = sd_event_default(&g->event);
237 if (r < 0)
238 return r;
239 }
240
241 g->curl = curl_multi_init();
242 if (!g->curl)
6
Assuming field 'curl' is null
7
Taking true branch
243 return -ENOMEM12;
8
Potential leak of memory pointed to by 'g'
244
245 if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETDATA, g)curl_multi_setopt(g->curl,CURLMOPT_SOCKETDATA,g) != CURLM_OK)
246 return -EINVAL22;
247
248 if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETFUNCTION, curl_glue_socket_callback)curl_multi_setopt(g->curl,CURLMOPT_SOCKETFUNCTION,curl_glue_socket_callback
)
!= CURLM_OK)
249 return -EINVAL22;
250
251 if (curl_multi_setopt(g->curl, CURLMOPT_TIMERDATA, g)curl_multi_setopt(g->curl,CURLMOPT_TIMERDATA,g) != CURLM_OK)
252 return -EINVAL22;
253
254 if (curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback)curl_multi_setopt(g->curl,CURLMOPT_TIMERFUNCTION,curl_glue_timer_callback
)
!= CURLM_OK)
255 return -EINVAL22;
256
257 *glue = TAKE_PTR(g)({ typeof(g) _ptr_ = (g); (g) = ((void*)0); _ptr_; });
258
259 return 0;
260}
261
262int curl_glue_make(CURL **ret, const char *url, void *userdata) {
263 const char *useragent;
264 CURL *c;
265 int r;
266
267 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/import/curl-util.c", 267
, __PRETTY_FUNCTION__); } while (0)
;
268 assert(url)do { if ((__builtin_expect(!!(!(url)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("url"), "../src/import/curl-util.c", 268
, __PRETTY_FUNCTION__); } while (0)
;
269
270 c = curl_easy_init();
271 if (!c)
272 return -ENOMEM12;
273
274 /* curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); */
275
276 if (curl_easy_setopt(c, CURLOPT_URL, url)curl_easy_setopt(c,CURLOPT_URL,url) != CURLE_OK) {
277 r = -EIO5;
278 goto fail;
279 }
280
281 if (curl_easy_setopt(c, CURLOPT_PRIVATE, userdata)curl_easy_setopt(c,CURLOPT_PRIVATE,userdata) != CURLE_OK) {
282 r = -EIO5;
283 goto fail;
284 }
285
286 useragent = strjoina(program_invocation_short_name, "/" PACKAGE_VERSION)({ const char *_appendees_[] = { program_invocation_short_name
, "/" "239" }; 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_; })
;
287 if (curl_easy_setopt(c, CURLOPT_USERAGENT, useragent)curl_easy_setopt(c,CURLOPT_USERAGENT,useragent) != CURLE_OK) {
288 r = -EIO5;
289 goto fail;
290 }
291
292 if (curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L)curl_easy_setopt(c,CURLOPT_FOLLOWLOCATION,1L) != CURLE_OK) {
293 r = -EIO5;
294 goto fail;
295 }
296
297 *ret = c;
298 return 0;
299
300fail:
301 curl_easy_cleanup(c);
302 return r;
303}
304
305int curl_glue_add(CurlGlue *g, CURL *c) {
306 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 306, __PRETTY_FUNCTION__
); } while (0)
;
307 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/import/curl-util.c", 307, __PRETTY_FUNCTION__
); } while (0)
;
308
309 if (curl_multi_add_handle(g->curl, c) != CURLM_OK)
310 return -EIO5;
311
312 return 0;
313}
314
315void curl_glue_remove_and_free(CurlGlue *g, CURL *c) {
316 assert(g)do { if ((__builtin_expect(!!(!(g)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("g"), "../src/import/curl-util.c", 316, __PRETTY_FUNCTION__
); } while (0)
;
317
318 if (!c)
319 return;
320
321 if (g->curl)
322 curl_multi_remove_handle(g->curl, c);
323
324 curl_easy_cleanup(c);
325}
326
327struct curl_slist *curl_slist_new(const char *first, ...) {
328 struct curl_slist *l;
329 va_list ap;
330
331 if (!first)
332 return NULL((void*)0);
333
334 l = curl_slist_append(NULL((void*)0), first);
335 if (!l)
336 return NULL((void*)0);
337
338 va_start(ap, first)__builtin_va_start(ap, first);
339
340 for (;;) {
341 struct curl_slist *n;
342 const char *i;
343
344 i = va_arg(ap, const char*)__builtin_va_arg(ap, const char*);
345 if (!i)
346 break;
347
348 n = curl_slist_append(l, i);
349 if (!n) {
350 va_end(ap)__builtin_va_end(ap);
351 curl_slist_free_all(l);
352 return NULL((void*)0);
353 }
354
355 l = n;
356 }
357
358 va_end(ap)__builtin_va_end(ap);
359 return l;
360}
361
362int curl_header_strdup(const void *contents, size_t sz, const char *field, char **value) {
363 const char *p;
364 char *s;
365
366 p = memory_startswith(contents, sz, field);
367 if (!p)
368 return 0;
369
370 sz -= p - (const char*) contents;
371
372 if (memchr(p, 0, sz))
373 return 0;
374
375 /* Skip over preceeding whitespace */
376 while (sz > 0 && strchr(WHITESPACE" \t\n\r", p[0])) {
377 p++;
378 sz--;
379 }
380
381 /* Truncate trailing whitespace */
382 while (sz > 0 && strchr(WHITESPACE" \t\n\r", p[sz-1]))
383 sz--;
384
385 s = strndup(p, sz);
386 if (!s)
387 return -ENOMEM12;
388
389 *value = s;
390 return 1;
391}
392
393int curl_parse_http_time(const char *t, usec_t *ret) {
394 _cleanup_(freelocalep)__attribute__((cleanup(freelocalep))) locale_t loc = (locale_t) 0;
395 const char *e;
396 struct tm tm;
397 time_t v;
398
399 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/import/curl-util.c", 399, __PRETTY_FUNCTION__
); } while (0)
;
400 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/import/curl-util.c", 400
, __PRETTY_FUNCTION__); } while (0)
;
401
402 loc = newlocale(LC_TIME_MASK(1 << 2), "C", (locale_t) 0);
403 if (loc == (locale_t) 0)
404 return -errno(*__errno_location ());
405
406 /* RFC822 */
407 e = strptime_l(t, "%a, %d %b %Y %H:%M:%S %Z", &tm, loc);
408 if (!e || *e != 0)
409 /* RFC 850 */
410 e = strptime_l(t, "%A, %d-%b-%y %H:%M:%S %Z", &tm, loc);
411 if (!e || *e != 0)
412 /* ANSI C */
413 e = strptime_l(t, "%a %b %d %H:%M:%S %Y", &tm, loc);
414 if (!e || *e != 0)
415 return -EINVAL22;
416
417 v = timegm(&tm);
418 if (v == (time_t) -1)
419 return -EINVAL22;
420
421 *ret = (usec_t) v * USEC_PER_SEC((usec_t) 1000000ULL);
422 return 0;
423}