| File: | build-scan/../src/shared/cgroup-show.c |
| Warning: | line 247, column 32 Potential leak of memory pointed to by 'copy' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
| 2 | |||||
| 3 | #include <dirent.h> | ||||
| 4 | #include <errno(*__errno_location ()).h> | ||||
| 5 | #include <stddef.h> | ||||
| 6 | #include <stdio.h> | ||||
| 7 | #include <stdlib.h> | ||||
| 8 | #include <string.h> | ||||
| 9 | |||||
| 10 | #include "alloc-util.h" | ||||
| 11 | #include "bus-error.h" | ||||
| 12 | #include "bus-util.h" | ||||
| 13 | #include "cgroup-show.h" | ||||
| 14 | #include "cgroup-util.h" | ||||
| 15 | #include "fd-util.h" | ||||
| 16 | #include "fileio.h" | ||||
| 17 | #include "format-util.h" | ||||
| 18 | #include "locale-util.h" | ||||
| 19 | #include "macro.h" | ||||
| 20 | #include "output-mode.h" | ||||
| 21 | #include "path-util.h" | ||||
| 22 | #include "process-util.h" | ||||
| 23 | #include "string-util.h" | ||||
| 24 | #include "terminal-util.h" | ||||
| 25 | #include "unit-name.h" | ||||
| 26 | |||||
| 27 | static void show_pid_array( | ||||
| 28 | pid_t pids[], | ||||
| 29 | unsigned n_pids, | ||||
| 30 | const char *prefix, | ||||
| 31 | unsigned n_columns, | ||||
| 32 | bool_Bool extra, | ||||
| 33 | bool_Bool more, | ||||
| 34 | OutputFlags flags) { | ||||
| 35 | |||||
| 36 | unsigned i, j, pid_width; | ||||
| 37 | |||||
| 38 | if (n_pids == 0) | ||||
| 39 | return; | ||||
| 40 | |||||
| 41 | qsort(pids, n_pids, sizeof(pid_t), pid_compare_func); | ||||
| 42 | |||||
| 43 | /* Filter duplicates */ | ||||
| 44 | for (j = 0, i = 1; i < n_pids; i++) { | ||||
| 45 | if (pids[i] == pids[j]) | ||||
| 46 | continue; | ||||
| 47 | pids[++j] = pids[i]; | ||||
| 48 | } | ||||
| 49 | n_pids = j + 1; | ||||
| 50 | pid_width = DECIMAL_STR_WIDTH(pids[j])({ typeof(pids[j]) _x_ = (pids[j]); unsigned ans = 1; while ( (_x_ /= 10) != 0) ans++; ans; }); | ||||
| 51 | |||||
| 52 | if (flags & OUTPUT_FULL_WIDTH) | ||||
| 53 | n_columns = 0; | ||||
| 54 | else { | ||||
| 55 | if (n_columns > pid_width+2) | ||||
| 56 | n_columns -= pid_width+2; | ||||
| 57 | else | ||||
| 58 | n_columns = 20; | ||||
| 59 | } | ||||
| 60 | for (i = 0; i < n_pids; i++) { | ||||
| 61 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | ||||
| 62 | |||||
| 63 | (void) get_process_cmdline(pids[i], n_columns, true1, &t); | ||||
| 64 | |||||
| 65 | if (extra) | ||||
| 66 | printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET)); | ||||
| 67 | else | ||||
| 68 | printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT))); | ||||
| 69 | |||||
| 70 | printf("%*"PID_PRI"i"" %s\n", pid_width, pids[i], strna(t)); | ||||
| 71 | } | ||||
| 72 | } | ||||
| 73 | |||||
| 74 | static int show_cgroup_one_by_path( | ||||
| 75 | const char *path, | ||||
| 76 | const char *prefix, | ||||
| 77 | unsigned n_columns, | ||||
| 78 | bool_Bool more, | ||||
| 79 | OutputFlags flags) { | ||||
| 80 | |||||
| 81 | char *fn; | ||||
| 82 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | ||||
| 83 | size_t n = 0, n_allocated = 0; | ||||
| 84 | _cleanup_free___attribute__((cleanup(freep))) pid_t *pids = NULL((void*)0); | ||||
| 85 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||
| 86 | pid_t pid; | ||||
| 87 | int r; | ||||
| 88 | |||||
| 89 | r = cg_mangle_path(path, &p); | ||||
| 90 | if (r < 0) | ||||
| 91 | return r; | ||||
| 92 | |||||
| 93 | fn = strjoina(p, "/cgroup.procs")({ const char *_appendees_[] = { p, "/cgroup.procs" }; 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_; }); | ||||
| 94 | f = fopen(fn, "re"); | ||||
| 95 | if (!f) | ||||
| 96 | return -errno(*__errno_location ()); | ||||
| 97 | |||||
| 98 | while ((r = cg_read_pid(f, &pid)) > 0) { | ||||
| 99 | |||||
| 100 | if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0) | ||||
| 101 | continue; | ||||
| 102 | |||||
| 103 | if (!GREEDY_REALLOC(pids, n_allocated, n + 1)greedy_realloc((void**) &(pids), &(n_allocated), (n + 1), sizeof((pids)[0]))) | ||||
| 104 | return -ENOMEM12; | ||||
| 105 | |||||
| 106 | assert(n < n_allocated)do { if ((__builtin_expect(!!(!(n < n_allocated)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n < n_allocated"), "../src/shared/cgroup-show.c" , 106, __PRETTY_FUNCTION__); } while (0); | ||||
| 107 | pids[n++] = pid; | ||||
| 108 | } | ||||
| 109 | |||||
| 110 | if (r < 0) | ||||
| 111 | return r; | ||||
| 112 | |||||
| 113 | show_pid_array(pids, n, prefix, n_columns, false0, more, flags); | ||||
| 114 | |||||
| 115 | return 0; | ||||
| 116 | } | ||||
| 117 | |||||
| 118 | int show_cgroup_by_path( | ||||
| 119 | const char *path, | ||||
| 120 | const char *prefix, | ||||
| 121 | unsigned n_columns, | ||||
| 122 | OutputFlags flags) { | ||||
| 123 | |||||
| 124 | _cleanup_free___attribute__((cleanup(freep))) char *fn = NULL((void*)0), *p1 = NULL((void*)0), *last = NULL((void*)0), *p2 = NULL((void*)0); | ||||
| 125 | _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0); | ||||
| 126 | char *gn = NULL((void*)0); | ||||
| 127 | bool_Bool shown_pids = false0; | ||||
| 128 | int r; | ||||
| 129 | |||||
| 130 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/cgroup-show.c", 130 , __PRETTY_FUNCTION__); } while (0); | ||||
| 131 | |||||
| 132 | if (n_columns <= 0) | ||||
| 133 | n_columns = columns(); | ||||
| 134 | |||||
| 135 | prefix = strempty(prefix); | ||||
| 136 | |||||
| 137 | r = cg_mangle_path(path, &fn); | ||||
| 138 | if (r < 0) | ||||
| 139 | return r; | ||||
| 140 | |||||
| 141 | d = opendir(fn); | ||||
| 142 | if (!d) | ||||
| 143 | return -errno(*__errno_location ()); | ||||
| 144 | |||||
| 145 | while ((r = cg_read_subgroup(d, &gn)) > 0) { | ||||
| 146 | _cleanup_free___attribute__((cleanup(freep))) char *k = NULL((void*)0); | ||||
| 147 | |||||
| 148 | k = strjoin(fn, "/", gn)strjoin_real((fn), "/", gn, ((void*)0)); | ||||
| 149 | free(gn); | ||||
| 150 | if (!k) | ||||
| 151 | return -ENOMEM12; | ||||
| 152 | |||||
| 153 | if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL((void*)0), k) > 0) | ||||
| 154 | continue; | ||||
| 155 | |||||
| 156 | if (!shown_pids) { | ||||
| 157 | show_cgroup_one_by_path(path, prefix, n_columns, true1, flags); | ||||
| 158 | shown_pids = true1; | ||||
| 159 | } | ||||
| 160 | |||||
| 161 | if (last) { | ||||
| 162 | printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last))); | ||||
| 163 | |||||
| 164 | if (!p1) { | ||||
| 165 | p1 = strappend(prefix, special_glyph(TREE_VERTICAL)); | ||||
| 166 | if (!p1) | ||||
| 167 | return -ENOMEM12; | ||||
| 168 | } | ||||
| 169 | |||||
| 170 | show_cgroup_by_path(last, p1, n_columns-2, flags); | ||||
| 171 | free(last); | ||||
| 172 | } | ||||
| 173 | |||||
| 174 | last = TAKE_PTR(k)({ typeof(k) _ptr_ = (k); (k) = ((void*)0); _ptr_; }); | ||||
| 175 | } | ||||
| 176 | |||||
| 177 | if (r < 0) | ||||
| 178 | return r; | ||||
| 179 | |||||
| 180 | if (!shown_pids) | ||||
| 181 | show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags); | ||||
| 182 | |||||
| 183 | if (last) { | ||||
| 184 | printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last))); | ||||
| 185 | |||||
| 186 | if (!p2) { | ||||
| 187 | p2 = strappend(prefix, " "); | ||||
| 188 | if (!p2) | ||||
| 189 | return -ENOMEM12; | ||||
| 190 | } | ||||
| 191 | |||||
| 192 | show_cgroup_by_path(last, p2, n_columns-2, flags); | ||||
| 193 | } | ||||
| 194 | |||||
| 195 | return 0; | ||||
| 196 | } | ||||
| 197 | |||||
| 198 | int show_cgroup(const char *controller, | ||||
| 199 | const char *path, | ||||
| 200 | const char *prefix, | ||||
| 201 | unsigned n_columns, | ||||
| 202 | OutputFlags flags) { | ||||
| 203 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||
| 204 | int r; | ||||
| 205 | |||||
| 206 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/cgroup-show.c", 206 , __PRETTY_FUNCTION__); } while (0); | ||||
| 207 | |||||
| 208 | r = cg_get_path(controller, path, NULL((void*)0), &p); | ||||
| 209 | if (r < 0) | ||||
| 210 | return r; | ||||
| 211 | |||||
| 212 | return show_cgroup_by_path(p, prefix, n_columns, flags); | ||||
| 213 | } | ||||
| 214 | |||||
| 215 | static int show_extra_pids( | ||||
| 216 | const char *controller, | ||||
| 217 | const char *path, | ||||
| 218 | const char *prefix, | ||||
| 219 | unsigned n_columns, | ||||
| 220 | const pid_t pids[], | ||||
| 221 | unsigned n_pids, | ||||
| 222 | OutputFlags flags) { | ||||
| 223 | |||||
| 224 | _cleanup_free___attribute__((cleanup(freep))) pid_t *copy = NULL((void*)0); | ||||
| 225 | unsigned i, j; | ||||
| 226 | int r; | ||||
| 227 | |||||
| 228 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/cgroup-show.c", 228 , __PRETTY_FUNCTION__); } while (0); | ||||
| 229 | |||||
| 230 | if (n_pids <= 0) | ||||
| 231 | return 0; | ||||
| 232 | |||||
| 233 | if (n_columns
| ||||
| 234 | n_columns = columns(); | ||||
| 235 | |||||
| 236 | prefix = strempty(prefix); | ||||
| 237 | |||||
| 238 | copy = new(pid_t, n_pids)((pid_t*) malloc_multiply(sizeof(pid_t), (n_pids))); | ||||
| 239 | if (!copy) | ||||
| 240 | return -ENOMEM12; | ||||
| 241 | |||||
| 242 | for (i = 0, j = 0; i
| ||||
| 243 | _cleanup_free___attribute__((cleanup(freep))) char *k = NULL((void*)0); | ||||
| 244 | |||||
| 245 | r = cg_pid_get_path(controller, pids[i], &k); | ||||
| 246 | if (r < 0) | ||||
| 247 | return r; | ||||
| |||||
| 248 | |||||
| 249 | if (path_startswith(k, path)) | ||||
| 250 | continue; | ||||
| 251 | |||||
| 252 | copy[j++] = pids[i]; | ||||
| 253 | } | ||||
| 254 | |||||
| 255 | show_pid_array(copy, j, prefix, n_columns, true1, false0, flags); | ||||
| 256 | |||||
| 257 | return 0; | ||||
| 258 | } | ||||
| 259 | |||||
| 260 | int show_cgroup_and_extra( | ||||
| 261 | const char *controller, | ||||
| 262 | const char *path, | ||||
| 263 | const char *prefix, | ||||
| 264 | unsigned n_columns, | ||||
| 265 | const pid_t extra_pids[], | ||||
| 266 | unsigned n_extra_pids, | ||||
| 267 | OutputFlags flags) { | ||||
| 268 | |||||
| 269 | int r; | ||||
| 270 | |||||
| 271 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/cgroup-show.c", 271 , __PRETTY_FUNCTION__); } while (0); | ||||
| 272 | |||||
| 273 | r = show_cgroup(controller, path, prefix, n_columns, flags); | ||||
| 274 | if (r < 0) | ||||
| 275 | return r; | ||||
| 276 | |||||
| 277 | return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags); | ||||
| 278 | } | ||||
| 279 | |||||
| 280 | int show_cgroup_and_extra_by_spec( | ||||
| 281 | const char *spec, | ||||
| 282 | const char *prefix, | ||||
| 283 | unsigned n_columns, | ||||
| 284 | const pid_t extra_pids[], | ||||
| 285 | unsigned n_extra_pids, | ||||
| 286 | OutputFlags flags) { | ||||
| 287 | |||||
| 288 | _cleanup_free___attribute__((cleanup(freep))) char *controller = NULL((void*)0), *path = NULL((void*)0); | ||||
| 289 | int r; | ||||
| 290 | |||||
| 291 | assert(spec)do { if ((__builtin_expect(!!(!(spec)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("spec"), "../src/shared/cgroup-show.c", 291 , __PRETTY_FUNCTION__); } while (0); | ||||
| |||||
| 292 | |||||
| 293 | r = cg_split_spec(spec, &controller, &path); | ||||
| 294 | if (r < 0) | ||||
| 295 | return r; | ||||
| 296 | |||||
| 297 | return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags); | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | int show_cgroup_get_unit_path_and_warn( | ||||
| 301 | sd_bus *bus, | ||||
| 302 | const char *unit, | ||||
| 303 | char **ret) { | ||||
| 304 | |||||
| 305 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | ||||
| 306 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); | ||||
| 307 | int r; | ||||
| 308 | |||||
| 309 | path = unit_dbus_path_from_name(unit); | ||||
| 310 | if (!path) | ||||
| 311 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/shared/cgroup-show.c" , 311, __func__); | ||||
| 312 | |||||
| 313 | r = sd_bus_get_property_string( | ||||
| 314 | bus, | ||||
| 315 | "org.freedesktop.systemd1", | ||||
| 316 | path, | ||||
| 317 | unit_dbus_interface_from_name(unit), | ||||
| 318 | "ControlGroup", | ||||
| 319 | &error, | ||||
| 320 | ret); | ||||
| 321 | if (r < 0) | ||||
| 322 | return log_error_errno(r, "Failed to query unit control group path: %s",({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 323, __func__, "Failed to query unit control group path: %s" , bus_error_message(&error, r)) : -abs(_e); }) | ||||
| 323 | bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 323, __func__, "Failed to query unit control group path: %s" , bus_error_message(&error, r)) : -abs(_e); }); | ||||
| 324 | |||||
| 325 | return 0; | ||||
| 326 | } | ||||
| 327 | |||||
| 328 | int show_cgroup_get_path_and_warn( | ||||
| 329 | const char *machine, | ||||
| 330 | const char *prefix, | ||||
| 331 | char **ret) { | ||||
| 332 | |||||
| 333 | int r; | ||||
| 334 | _cleanup_free___attribute__((cleanup(freep))) char *root = NULL((void*)0); | ||||
| 335 | |||||
| 336 | if (machine) { | ||||
| 337 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | ||||
| 338 | _cleanup_free___attribute__((cleanup(freep))) char *unit = NULL((void*)0); | ||||
| 339 | const char *m; | ||||
| 340 | |||||
| 341 | m = strjoina("/run/systemd/machines/", machine)({ const char *_appendees_[] = { "/run/systemd/machines/", machine }; 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_; }); | ||||
| 342 | r = parse_env_file(NULL((void*)0), m, NEWLINE"\n\r", "SCOPE", &unit, NULL((void*)0)); | ||||
| 343 | if (r < 0) | ||||
| 344 | return log_error_errno(r, "Failed to load machine data: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 344, __func__, "Failed to load machine data: %m" ) : -abs(_e); }); | ||||
| 345 | |||||
| 346 | r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL((void*)0), false0, &bus); | ||||
| 347 | if (r < 0) | ||||
| 348 | return log_error_errno(r, "Failed to create bus connection: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 348, __func__, "Failed to create bus connection: %m" ) : -abs(_e); }); | ||||
| 349 | |||||
| 350 | r = show_cgroup_get_unit_path_and_warn(bus, unit, &root); | ||||
| 351 | if (r < 0) | ||||
| 352 | return r; | ||||
| 353 | } else { | ||||
| 354 | r = cg_get_root_path(&root); | ||||
| 355 | if (r == -ENOMEDIUM123) | ||||
| 356 | return log_error_errno(r, "Failed to get root control group path.\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 357, __func__, "Failed to get root control group path.\n" "No cgroup filesystem mounted on /sys/fs/cgroup") : -abs(_e) ; }) | ||||
| 357 | "No cgroup filesystem mounted on /sys/fs/cgroup")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 357, __func__, "Failed to get root control group path.\n" "No cgroup filesystem mounted on /sys/fs/cgroup") : -abs(_e) ; }); | ||||
| 358 | else if (r < 0) | ||||
| 359 | return log_error_errno(r, "Failed to get root control group path: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/shared/cgroup-show.c", 359, __func__, "Failed to get root control group path: %m" ) : -abs(_e); }); | ||||
| 360 | } | ||||
| 361 | |||||
| 362 | if (prefix) { | ||||
| 363 | char *t; | ||||
| 364 | |||||
| 365 | t = strjoin(root, prefix)strjoin_real((root), prefix, ((void*)0)); | ||||
| 366 | if (!t) | ||||
| 367 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/shared/cgroup-show.c" , 367, __func__); | ||||
| 368 | |||||
| 369 | *ret = t; | ||||
| 370 | } else | ||||
| 371 | *ret = TAKE_PTR(root)({ typeof(root) _ptr_ = (root); (root) = ((void*)0); _ptr_; } ); | ||||
| 372 | |||||
| 373 | return 0; | ||||
| 374 | } |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | #include <alloca.h> |
| 5 | #include <stddef.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include "macro.h" |
| 10 | |
| 11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
| 12 | |
| 13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
| 14 | |
| 15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
| 16 | ({ \ |
| 17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
| 18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
| 19 | }) |
| 20 | |
| 21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
| 22 | ({ \ |
| 23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
| 24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
| 25 | }) |
| 26 | |
| 27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
| 28 | |
| 29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
| 30 | |
| 31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
| 32 | |
| 33 | static inline void *mfree(void *memory) { |
| 34 | free(memory); |
| 35 | return NULL((void*)0); |
| 36 | } |
| 37 | |
| 38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
| 39 | ({ \ |
| 40 | free(a); \ |
| 41 | (a) = (b); \ |
| 42 | (b) = NULL((void*)0); \ |
| 43 | 0; \ |
| 44 | }) |
| 45 | |
| 46 | void* memdup(const void *p, size_t l) _alloc_(2); |
| 47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
| 48 | |
| 49 | static inline void freep(void *p) { |
| 50 | free(*(void**) p); |
| 51 | } |
| 52 | |
| 53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
| 54 | |
| 55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
| 56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
| 57 | } |
| 58 | |
| 59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
| 60 | if (size_multiply_overflow(size, need)) |
| 61 | return NULL((void*)0); |
| 62 | |
| 63 | return malloc(size * need); |
| 64 | } |
| 65 | |
| 66 | #if !HAVE_REALLOCARRAY1 |
| 67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
| 68 | if (size_multiply_overflow(size, need)) |
| 69 | return NULL((void*)0); |
| 70 | |
| 71 | return realloc(p, size * need); |
| 72 | } |
| 73 | #endif |
| 74 | |
| 75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
| 76 | if (size_multiply_overflow(size, need)) |
| 77 | return NULL((void*)0); |
| 78 | |
| 79 | return memdup(p, size * need); |
| 80 | } |
| 81 | |
| 82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
| 83 | if (size_multiply_overflow(size, need)) |
| 84 | return NULL((void*)0); |
| 85 | |
| 86 | return memdup_suffix0(p, size * need); |
| 87 | } |
| 88 | |
| 89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
| 90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
| 91 | |
| 92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 94 | |
| 95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 97 | |
| 98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
| 99 | ({ \ |
| 100 | char *_new_; \ |
| 101 | size_t _len_ = n; \ |
| 102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
| 103 | (void *) memset(_new_, 0, _len_); \ |
| 104 | }) |
| 105 | |
| 106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
| 107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
| 108 | ({ \ |
| 109 | void *_ptr_; \ |
| 110 | size_t _mask_ = (align) - 1; \ |
| 111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
| 112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
| 113 | }) |
| 114 | |
| 115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
| 116 | ({ \ |
| 117 | void *_new_; \ |
| 118 | size_t _size_ = (size); \ |
| 119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
| 120 | (void*)memset(_new_, 0, _size_); \ |
| 121 | }) |
| 122 | |
| 123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
| 124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
| 125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
| 126 | ({ \ |
| 127 | typeof(ptr) _ptr_ = (ptr); \ |
| 128 | (ptr) = NULL((void*)0); \ |
| 129 | _ptr_; \ |
| 130 | }) |