Bug Summary

File:build-scan/../src/shared/fstab-util.c
Warning:line 244, column 24
Potential leak of memory pointed to by 'u'

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 fstab-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 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/shared/libsystemd-shared-239.a.p -I src/shared -I ../src/shared -I src/basic -I ../src/basic -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 .. -I /usr/include/blkid -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/shared/fstab-util.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <mntent.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "alloc-util.h"
10#include "device-nodes.h"
11#include "fstab-util.h"
12#include "macro.h"
13#include "mount-util.h"
14#include "parse-util.h"
15#include "path-util.h"
16#include "string-util.h"
17#include "strv.h"
18#include "util.h"
19
20int fstab_has_fstype(const char *fstype) {
21 _cleanup_endmntent___attribute__((cleanup(endmntentp))) FILE *f = NULL((void*)0);
22 struct mntent *m;
23
24 f = setmntent("/etc/fstab", "re");
25 if (!f)
26 return errno(*__errno_location ()) == ENOENT2 ? false0 : -errno(*__errno_location ());
27
28 for (;;) {
29 errno(*__errno_location ()) = 0;
30 m = getmntent(f);
31 if (!m)
32 return errno(*__errno_location ()) != 0 ? -errno(*__errno_location ()) : false0;
33
34 if (streq(m->mnt_type, fstype)(strcmp((m->mnt_type),(fstype)) == 0))
35 return true1;
36 }
37 return false0;
38}
39
40int fstab_is_mount_point(const char *mount) {
41 _cleanup_endmntent___attribute__((cleanup(endmntentp))) FILE *f = NULL((void*)0);
42 struct mntent *m;
43
44 f = setmntent("/etc/fstab", "re");
45 if (!f)
46 return errno(*__errno_location ()) == ENOENT2 ? false0 : -errno(*__errno_location ());
47
48 for (;;) {
49 errno(*__errno_location ()) = 0;
50 m = getmntent(f);
51 if (!m)
52 return errno(*__errno_location ()) != 0 ? -errno(*__errno_location ()) : false0;
53
54 if (path_equal(m->mnt_dir, mount))
55 return true1;
56 }
57 return false0;
58}
59
60int fstab_filter_options(const char *opts, const char *names,
61 const char **namefound, char **value, char **filtered) {
62 const char *name, *n = NULL((void*)0), *x;
63 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **stor = NULL((void*)0);
64 _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0), **strv = NULL((void*)0);
65
66 assert(names && *names)do { if ((__builtin_expect(!!(!(names && *names)),0))
) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("names && *names"
), "../src/shared/fstab-util.c", 66, __PRETTY_FUNCTION__); } while
(0)
;
67
68 if (!opts)
69 goto answer;
70
71 /* If !value and !filtered, this function is not allowed to fail. */
72
73 if (!filtered) {
74 const char *word, *state;
75 size_t l;
76
77 FOREACH_WORD_SEPARATOR(word, l, opts, ",", state)for ((state) = (opts), (word) = split(&(state), &(l),
(","), (0)); (word); (word) = split(&(state), &(l), (
","), (0)))
78 NULSTR_FOREACH(name, names)for ((name) = (names); (name) && *(name); (name) = strchr
((name), 0)+1)
{
79 if (l < strlen(name))
80 continue;
81 if (!strneq(word, name, strlen(name))(strncmp((word), (name), (strlen(name))) == 0))
82 continue;
83
84 /* we know that the string is NUL
85 * terminated, so *x is valid */
86 x = word + strlen(name);
87 if (IN_SET(*x, '\0', '=', ',')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'\0', '=', ','})/sizeof(int)]; switch(*x
) { case '\0': case '=': case ',': _found = 1; break; default
: break; } _found; })
) {
88 n = name;
89 if (value) {
90 free(v);
91 if (IN_SET(*x, '\0', ',')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'\0', ','})/sizeof(int)]; switch(*x) { case
'\0': case ',': _found = 1; break; default: break; } _found;
})
)
92 v = NULL((void*)0);
93 else {
94 assert(*x == '=')do { if ((__builtin_expect(!!(!(*x == '=')),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("*x == '='"), "../src/shared/fstab-util.c"
, 94, __PRETTY_FUNCTION__); } while (0)
;
95 x++;
96 v = strndup(x, l - strlen(name) - 1);
97 if (!v)
98 return -ENOMEM12;
99 }
100 }
101 }
102 }
103 } else {
104 char **t, **s;
105
106 stor = strv_split(opts, ",");
107 if (!stor)
108 return -ENOMEM12;
109 strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
110 if (!strv)
111 return -ENOMEM12;
112
113 for (s = t = strv; *s; s++) {
114 NULSTR_FOREACH(name, names)for ((name) = (names); (name) && *(name); (name) = strchr
((name), 0)+1)
{
115 x = startswith(*s, name);
116 if (x && IN_SET(*x, '\0', '=')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'\0', '='})/sizeof(int)]; switch(*x) { case
'\0': case '=': _found = 1; break; default: break; } _found;
})
)
117 goto found;
118 }
119
120 *t = *s;
121 t++;
122 continue;
123 found:
124 /* Keep the last occurence found */
125 n = name;
126 if (value) {
127 free(v);
128 if (*x == '\0')
129 v = NULL((void*)0);
130 else {
131 assert(*x == '=')do { if ((__builtin_expect(!!(!(*x == '=')),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("*x == '='"), "../src/shared/fstab-util.c"
, 131, __PRETTY_FUNCTION__); } while (0)
;
132 x++;
133 v = strdup(x);
134 if (!v)
135 return -ENOMEM12;
136 }
137 }
138 }
139 *t = NULL((void*)0);
140 }
141
142answer:
143 if (namefound)
144 *namefound = n;
145 if (filtered) {
146 char *f;
147
148 f = strv_join(strv, ",");
149 if (!f)
150 return -ENOMEM12;
151
152 *filtered = f;
153 }
154 if (value)
155 *value = TAKE_PTR(v)({ typeof(v) _ptr_ = (v); (v) = ((void*)0); _ptr_; });
156
157 return !!n;
158}
159
160int fstab_extract_values(const char *opts, const char *name, char ***values) {
161 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **optsv = NULL((void*)0), **res = NULL((void*)0);
162 char **s;
163
164 assert(opts)do { if ((__builtin_expect(!!(!(opts)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("opts"), "../src/shared/fstab-util.c", 164
, __PRETTY_FUNCTION__); } while (0)
;
165 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/fstab-util.c", 165
, __PRETTY_FUNCTION__); } while (0)
;
166 assert(values)do { if ((__builtin_expect(!!(!(values)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("values"), "../src/shared/fstab-util.c",
166, __PRETTY_FUNCTION__); } while (0)
;
167
168 optsv = strv_split(opts, ",");
169 if (!optsv)
170 return -ENOMEM12;
171
172 STRV_FOREACH(s, optsv)for ((s) = (optsv); (s) && *(s); (s)++) {
173 char *arg;
174 int r;
175
176 arg = startswith(*s, name);
177 if (!arg || *arg != '=')
178 continue;
179 r = strv_extend(&res, arg + 1);
180 if (r < 0)
181 return r;
182 }
183
184 *values = TAKE_PTR(res)({ typeof(res) _ptr_ = (res); (res) = ((void*)0); _ptr_; });
185
186 return !!*values;
187}
188
189int fstab_find_pri(const char *options, int *ret) {
190 _cleanup_free___attribute__((cleanup(freep))) char *opt = NULL((void*)0);
191 int r;
192 unsigned pri;
193
194 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/shared/fstab-util.c", 194
, __PRETTY_FUNCTION__); } while (0)
;
195
196 r = fstab_filter_options(options, "pri\0", NULL((void*)0), &opt, NULL((void*)0));
197 if (r < 0)
198 return r;
199 if (r == 0 || !opt)
200 return 0;
201
202 r = safe_atou(opt, &pri);
203 if (r < 0)
204 return r;
205
206 if ((int) pri < 0)
207 return -ERANGE34;
208
209 *ret = (int) pri;
210 return 1;
211}
212
213static char *unquote(const char *s, const char* quotes) {
214 size_t l;
215 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/shared/fstab-util.c", 215,
__PRETTY_FUNCTION__); } while (0)
;
7
Taking false branch
8
Loop condition is false. Exiting loop
216
217 /* This is rather stupid, simply removes the heading and
218 * trailing quotes if there is one. Doesn't care about
219 * escaping or anything.
220 *
221 * DON'T USE THIS FOR NEW CODE ANYMORE! */
222
223 l = strlen(s);
224 if (l < 2)
9
Assuming 'l' is >= 2
10
Taking false branch
225 return strdup(s);
226
227 if (strchr(quotes, s[0]) && s[l-1] == s[0])
11
Assuming the condition is false
228 return strndup(s+1, l-2);
229
230 return strdup(s);
12
Memory is allocated
231}
232
233static char *tag_to_udev_node(const char *tagvalue, const char *by) {
234 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0), *u = NULL((void*)0);
235 size_t enc_len;
236
237 u = unquote(tagvalue, QUOTES"\"\'");
6
Calling 'unquote'
13
Returned allocated memory
238 if (!u)
14
Assuming 'u' is non-null
15
Taking false branch
239 return NULL((void*)0);
240
241 enc_len = strlen(u) * 4 + 1;
242 t = new(char, enc_len)((char*) malloc_multiply(sizeof(char), (enc_len)));
243 if (!t)
16
Assuming 't' is null
17
Taking true branch
244 return NULL((void*)0);
18
Potential leak of memory pointed to by 'u'
245
246 if (encode_devnode_name(u, t, enc_len) < 0)
247 return NULL((void*)0);
248
249 return strjoin("/dev/disk/by-", by, "/", t)strjoin_real(("/dev/disk/by-"), by, "/", t, ((void*)0));
250}
251
252char *fstab_node_to_udev_node(const char *p) {
253 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/fstab-util.c", 253,
__PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'p' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
254
255 if (startswith(p, "LABEL="))
4
Taking true branch
256 return tag_to_udev_node(p+6, "label");
5
Calling 'tag_to_udev_node'
257
258 if (startswith(p, "UUID="))
259 return tag_to_udev_node(p+5, "uuid");
260
261 if (startswith(p, "PARTUUID="))
262 return tag_to_udev_node(p+9, "partuuid");
263
264 if (startswith(p, "PARTLABEL="))
265 return tag_to_udev_node(p+10, "partlabel");
266
267 return strdup(p);
268}