Bug Summary

File:src/lib/libfuse/fuse_opt.c
Warning:line 212, column 4
Value stored to 'keyval' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name fuse_opt.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 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libfuse/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/lib/libfuse -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libfuse/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libfuse/fuse_opt.c
1/* $OpenBSD: fuse_opt.c,v 1.26 2018/05/15 11:57:32 helg Exp $ */
2/*
3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
4 * Copyright (c) 2013 Stefan Sperling <stsp@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <assert.h>
20#include <stdint.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "debug.h"
25#include "fuse_opt.h"
26#include "fuse_private.h"
27
28#define IFUSE_OPT_DISCARD0 0
29#define IFUSE_OPT_KEEP1 1
30#define IFUSE_OPT_NEED_ANOTHER_ARG2 2
31
32static void
33free_argv(char **argv, int argc)
34{
35 int i;
36
37 for (i = 0; i < argc; i++)
38 free(argv[i]);
39 free(argv);
40}
41
42static int
43alloc_argv(struct fuse_args *args)
44{
45 char **argv;
46 int i;
47
48 assert(!args->allocated)((!args->allocated) ? (void)0 : __assert2("/usr/src/lib/libfuse/fuse_opt.c"
, 48, __func__, "!args->allocated"))
;
49
50 argv = calloc(args->argc, sizeof(*argv));
51 if (argv == NULL((void *)0))
52 return (-1);
53
54 if (args->argv) {
55 for (i = 0; i < args->argc; i++) {
56 argv[i] = strdup(args->argv[i]);
57 if (argv[i] == NULL((void *)0)) {
58 free_argv(argv, i + 1);
59 return (-1);
60 }
61 }
62 }
63
64 args->allocated = 1;
65 args->argv = argv;
66
67 return (0);
68}
69
70/*
71 * Returns the number of characters that matched for bounds checking later.
72 */
73static size_t
74match_opt(const char *templ, const char *opt)
75{
76 size_t sep, len;
77
78 len = strlen(templ);
79 sep = strcspn(templ, "=");
80
81 if (sep == len)
82 sep = strcspn(templ, " ");
83
84 /* key=, key=%, "-k ", -k % */
85 if (sep < len && (templ[sep + 1] == '\0' || templ[sep + 1] == '%')) {
86 if (strncmp(opt, templ, sep) == 0)
87 return (sep);
88 else
89 return (0);
90 }
91
92 if (strcmp(opt, templ) == 0)
93 return (len);
94
95 return (0);
96}
97
98static int
99add_opt(char **opts, const char *opt)
100{
101 char *new_opts;
102
103 if (*opts == NULL((void *)0)) {
104 *opts = strdup(opt);
105 if (*opts == NULL((void *)0))
106 return (-1);
107 return (0);
108 }
109
110 if (asprintf(&new_opts, "%s,%s", *opts, opt) == -1)
111 return (-1);
112
113 free(*opts);
114 *opts = new_opts;
115 return (0);
116}
117
118int
119fuse_opt_add_opt(char **opts, const char *opt)
120{
121 int ret;
122
123 if (opt == NULL((void *)0) || opt[0] == '\0')
124 return (-1);
125
126 ret = add_opt(opts, opt);
127 return (ret);
128}
129
130int
131fuse_opt_add_opt_escaped(char **opts, const char *opt)
132{
133 size_t size = 0, escaped = 0;
134 const char *s = opt;
135 char *escaped_opt, *p;
136 int ret;
137
138 if (opt == NULL((void *)0) || opt[0] == '\0')
139 return (-1);
140
141 while (*s) {
142 /* malloc(size + escaped) overflow check */
143 if (size >= (SIZE_MAX0xffffffffffffffffUL / 2))
144 return (-1);
145
146 if (*s == ',' || *s == '\\')
147 escaped++;
148 s++;
149 size++;
150 }
151 size++; /* trailing NUL */
152
153 if (escaped > 0) {
154 escaped_opt = malloc(size + escaped);
155 if (escaped_opt == NULL((void *)0))
156 return (-1);
157 s = opt;
158 p = escaped_opt;
159 while (*s) {
160 switch (*s) {
161 case ',':
162 case '\\':
163 *p++ = '\\';
164 /* FALLTHROUGH */
165 default:
166 *p++ = *s++;
167 }
168 }
169 *p = '\0';
170 } else {
171 escaped_opt = strdup(opt);
172 if (escaped_opt == NULL((void *)0))
173 return (-1);
174 }
175
176 ret = add_opt(opts, escaped_opt);
177 free(escaped_opt);
178 return (ret);
179}
180
181int
182fuse_opt_add_arg(struct fuse_args *args, const char *name)
183{
184 return (fuse_opt_insert_arg(args, args->argc, name));
185}
186DEF(fuse_opt_add_arg)__asm__(".global " "fuse_opt_add_arg" " ; " "fuse_opt_add_arg"
" = " "__fuse_opt_add_arg")
;
187
188static int
189parse_opt(const struct fuse_opt *o, const char *opt, void *data,
190 fuse_opt_proc_t f, struct fuse_args *arg)
191{
192 const char *val;
193 int keyval, ret, found;
194 size_t sep;
195
196 keyval = 0;
197 found = 0;
198
199 for(; o != NULL((void *)0) && o->templ; o++) {
200 sep = match_opt(o->templ, opt);
201 if (sep == 0)
202 continue;
203
204 found = 1;
205 val = opt;
206
207 /* check key=value or -p n */
208 if (o->templ[sep] == '=') {
209 keyval = 1;
210 val = &opt[sep + 1];
211 } else if (o->templ[sep] == ' ') {
212 keyval = 1;
Value stored to 'keyval' is never read
213 if (sep == strlen(opt)) {
214 /* ask for next arg to be included */
215 return (IFUSE_OPT_NEED_ANOTHER_ARG2);
216 } else if (strchr(o->templ, '%') != NULL((void *)0)) {
217 val = &opt[sep];
218 }
219 }
220
221 if (o->val == FUSE_OPT_KEY_DISCARD-4)
222 ret = IFUSE_OPT_DISCARD0;
223 else if (o->val == FUSE_OPT_KEY_KEEP-3)
224 ret = IFUSE_OPT_KEEP1;
225 else if (FUSE_OPT_IS_OPT_KEY(o)(o->off == (unsigned long)-1)) {
226 if (f == NULL((void *)0))
227 return (IFUSE_OPT_KEEP1);
228
229 ret = f(data, val, o->val, arg);
230 } else if (data == NULL((void *)0)) {
231 return (-1);
232 } else if (strchr(o->templ, '%') == NULL((void *)0)) {
233 *((int *)(data + o->off)) = o->val;
234 ret = IFUSE_OPT_DISCARD0;
235 } else if (strstr(o->templ, "%s") != NULL((void *)0)) {
236 *((char **)(data + o->off)) = strdup(val);
237 ret = IFUSE_OPT_DISCARD0;
238 } else {
239 /* All other templates, let sscanf deal with them. */
240 if (sscanf(opt, o->templ, data + o->off) != 1) {
241 fprintf(stderr(&__sF[2]), "fuse: Invalid value %s for "
242 "option %s\n", val, o->templ);
243 return (-1);
244 }
245 ret = IFUSE_OPT_DISCARD0;
246 }
247 }
248
249 if (found)
250 return (ret);
251
252 if (f != NULL((void *)0))
253 return f(data, opt, FUSE_OPT_KEY_OPT-1, arg);
254
255 return (IFUSE_OPT_KEEP1);
256}
257
258/*
259 * this code is not very sexy but we are forced to follow
260 * the fuse api.
261 *
262 * when f() returns 1 we need to keep the arg
263 * when f() returns 0 we need to discard the arg
264 */
265int
266fuse_opt_parse(struct fuse_args *args, void *data,
267 const struct fuse_opt *opt, fuse_opt_proc_t f)
268{
269 struct fuse_args outargs;
270 const char *arg, *ap;
271 char *optlist, *tofree;
272 int ret;
273 int i;
274
275 if (!args || !args->argc || !args->argv)
276 return (0);
277
278 memset(&outargs, 0, sizeof(outargs));
279 fuse_opt_add_arg(&outargs, args->argv[0]);
280
281 for (i = 1; i < args->argc; i++) {
282 arg = args->argv[i];
283 ret = 0;
284
285 /* not - and not -- */
286 if (arg[0] != '-') {
287 if (f == NULL((void *)0))
288 ret = IFUSE_OPT_KEEP1;
289 else
290 ret = f(data, arg, FUSE_OPT_KEY_NONOPT-2, &outargs);
291
292 if (ret == IFUSE_OPT_KEEP1)
293 fuse_opt_add_arg(&outargs, arg);
294 if (ret == -1)
295 goto err;
296 } else if (arg[1] == 'o') {
297 if (arg[2])
298 arg += 2; /* -ofoo,bar */
299 else {
300 if (++i >= args->argc)
301 goto err;
302
303 arg = args->argv[i];
304 }
305
306 tofree = optlist = strdup(arg);
307 if (optlist == NULL((void *)0))
308 goto err;
309
310 while ((ap = strsep(&optlist, ",")) != NULL((void *)0) &&
311 ret != -1) {
312 ret = parse_opt(opt, ap, data, f, &outargs);
313 if (ret == IFUSE_OPT_KEEP1) {
314 fuse_opt_add_arg(&outargs, "-o");
315 fuse_opt_add_arg(&outargs, ap);
316 }
317 }
318
319 free(tofree);
320
321 if (ret == -1)
322 goto err;
323 } else {
324 ret = parse_opt(opt, arg, data, f, &outargs);
325
326 if (ret == IFUSE_OPT_KEEP1)
327 fuse_opt_add_arg(&outargs, arg);
328 else if (ret == IFUSE_OPT_NEED_ANOTHER_ARG2) {
329 /* arg needs a value */
330 if (++i >= args->argc) {
331 fprintf(stderr(&__sF[2]), "fuse: missing argument after %s\n", arg);
332 goto err;
333 }
334
335 if (asprintf(&tofree, "%s%s", arg,
336 args->argv[i]) == -1)
337 goto err;
338
339 ret = parse_opt(opt, tofree, data, f, &outargs);
340 if (ret == IFUSE_OPT_KEEP1)
341 fuse_opt_add_arg(&outargs, tofree);
342 free(tofree);
343 }
344
345 if (ret == -1)
346 goto err;
347 }
348 }
349 ret = 0;
350
351err:
352 /* Update args */
353 fuse_opt_free_args(args);
354 args->allocated = outargs.allocated;
355 args->argc = outargs.argc;
356 args->argv = outargs.argv;
357 if (ret != 0)
358 ret = -1;
359
360 return (ret);
361}
362DEF(fuse_opt_parse)__asm__(".global " "fuse_opt_parse" " ; " "fuse_opt_parse" " = "
"__fuse_opt_parse")
;
363
364int
365fuse_opt_insert_arg(struct fuse_args *args, int p, const char *name)
366{
367 char **av;
368 char *this_arg, *next_arg;
369 int i;
370
371 if (name == NULL((void *)0))
372 return (-1);
373
374 if (!args->allocated && alloc_argv(args))
375 return (-1);
376
377 if (p < 0 || p > args->argc)
378 return (-1);
379
380 av = reallocarray(args->argv, args->argc + 2, sizeof(*av));
381 if (av == NULL((void *)0))
382 return (-1);
383
384 this_arg = strdup(name);
385 if (this_arg == NULL((void *)0)) {
386 free(av);
387 return (-1);
388 }
389
390 args->argc++;
391 args->argv = av;
392 args->argv[args->argc] = NULL((void *)0);
393 for (i = p; i < args->argc; i++) {
394 next_arg = args->argv[i];
395 args->argv[i] = this_arg;
396 this_arg = next_arg;
397 }
398 return (0);
399}
400DEF(fuse_opt_insert_arg)__asm__(".global " "fuse_opt_insert_arg" " ; " "fuse_opt_insert_arg"
" = " "__fuse_opt_insert_arg")
;
401
402void
403fuse_opt_free_args(struct fuse_args *args)
404{
405 if (!args->allocated)
406 return;
407
408 free_argv(args->argv, args->argc);
409 args->argv = 0;
410 args->argc = 0;
411 args->allocated = 0;
412}
413DEF(fuse_opt_free_args)__asm__(".global " "fuse_opt_free_args" " ; " "fuse_opt_free_args"
" = " "__fuse_opt_free_args")
;
414
415int
416fuse_opt_match(const struct fuse_opt *opts, const char *opt)
417{
418 const struct fuse_opt *this_opt = opts;
419
420 if (opt == NULL((void *)0) || opt[0] == '\0')
421 return (0);
422
423 while (this_opt->templ) {
424 if (match_opt(this_opt->templ, opt))
425 return (1);
426 this_opt++;
427 }
428
429 return (0);
430}
431DEF(fuse_opt_match)__asm__(".global " "fuse_opt_match" " ; " "fuse_opt_match" " = "
"__fuse_opt_match")
;