Bug Summary

File:src/usr.bin/radioctl/radioctl.c
Warning:line 413, column 12
Potential memory leak

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 radioctl.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 -pic-is-pie -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/usr.bin/radioctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/radioctl/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/usr.bin/radioctl/radioctl.c
1/* $OpenBSD: radioctl.c,v 1.20 2019/06/28 13:35:03 deraadt Exp $ */
2/* $RuOBSD: radioctl.c,v 1.4 2001/10/20 18:09:10 pva Exp $ */
3
4/*
5 * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/ioctl.h>
30#include <sys/radioio.h>
31
32#include <dev/ic/bt8xx.h>
33
34#include <err.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <ctype.h>
41
42#define RADIO_ENV"RADIODEVICE" "RADIODEVICE"
43#define RADIODEVICE"/dev/radio" "/dev/radio"
44
45const char *varname[] = {
46 "search",
47#define OPTION_SEARCH0x00 0x00
48 "volume",
49#define OPTION_VOLUME0x01 0x01
50 "frequency",
51#define OPTION_FREQUENCY0x02 0x02
52 "mute",
53#define OPTION_MUTE0x03 0x03
54 "reference",
55#define OPTION_REFERENCE0x04 0x04
56 "mono",
57#define OPTION_MONO0x05 0x05
58 "stereo",
59#define OPTION_STEREO0x06 0x06
60 "sensitivity",
61#define OPTION_SENSITIVITY0x07 0x07
62 "channel",
63#define OPTION_CHANNEL0x08 0x08
64 "chnlset"
65#define OPTION_CHNLSET0x09 0x09
66};
67
68#define OPTION_NONE~0u ~0u
69#define VALUE_NONE~0u ~0u
70
71struct opt_t {
72 char *string;
73 int option;
74 int sign;
75#define SIGN_NONE0 0
76#define SIGN_PLUS1 1
77#define SIGN_MINUS-1 -1
78 u_int32_t value;
79};
80
81struct chansets {
82 int value;
83 char *name;
84} chansets[] = {
85{ CHNLSET_NABCST1, "nabcst", },
86{ CHNLSET_CABLEIRC2, "cableirc", },
87{ CHNLSET_CABLEHRC3, "cablehrc", },
88{ CHNLSET_WEUROPE4, "weurope", },
89{ CHNLSET_JPNBCST5, "jpnbcst", },
90{ CHNLSET_JPNCABLE6, "jpncable", },
91{ CHNLSET_XUSSR7, "xussr", },
92{ CHNLSET_AUSTRALIA8, "australia", },
93{ CHNLSET_FRANCE9, "france", },
94{ 0, NULL((void *)0) }
95};
96
97extern char *__progname;
98const char *onchar = "on";
99#define ONCHAR_LEN2 2
100const char *offchar = "off";
101#define OFFCHAR_LEN3 3
102
103struct radio_info ri;
104unsigned int i = 0;
105
106int parse_opt(char *, struct opt_t *);
107
108void print_vars(int, int);
109void do_ioctls(int, struct opt_t *, int);
110
111void print_value(int, int);
112void change_value(const struct opt_t);
113void update_value(int, int *, int);
114
115void warn_unsupported(int);
116void usage(void);
117
118void show_verbose(const char *, int);
119void show_int_val(int, const char *, char *, int);
120void show_float_val(float, const char *, char *, int);
121void show_char_val(const char *, const char *, int);
122int str_to_opt(const char *);
123u_int str_to_int(char *, int);
124
125/*
126 * Control behavior of a FM tuner - set frequency, volume etc
127 */
128int
129main(int argc, char **argv)
130{
131 struct opt_t opt;
132 char **avp;
133
134 char *radiodev = NULL((void *)0);
135 int rd = -1;
136 int optchar;
137 int show_vars = 0;
138 int show_choices = 0;
139 int silent = 0;
140 int mode = O_RDONLY0x0000;
141
142 radiodev = getenv(RADIO_ENV"RADIODEVICE");
143 if (radiodev == NULL((void *)0))
1
Assuming 'radiodev' is not equal to NULL
2
Taking false branch
144 radiodev = RADIODEVICE"/dev/radio";
145
146 while ((optchar = getopt(argc, argv, "af:nvw")) != -1) {
3
Assuming the condition is false
4
Loop condition is false. Execution continues on line 169
147 switch (optchar) {
148 case 'a':
149 show_vars = 1;
150 break;
151 case 'f':
152 radiodev = optarg;
153 break;
154 case 'n':
155 silent = 1;
156 break;
157 case 'v':
158 show_choices = 1;
159 break;
160 case 'w':
161 /* backwards compatibility */
162 break;
163 default:
164 usage();
165 /* NOTREACHED */
166 }
167 }
168
169 argc -= optind;
170 argv += optind;
171
172 if (argc == 0)
5
Assuming 'argc' is not equal to 0
6
Taking false branch
173 show_vars = 1;
174
175 /*
176 * Scan the options for `name=value` so the
177 * device can be opened in the proper mode.
178 */
179 for (avp = argv; *avp != NULL((void *)0); avp++)
7
Loop condition is true. Entering loop body
180 if (strchr(*avp, '=') != NULL((void *)0)) {
8
Assuming the condition is true
9
Taking true branch
181 mode = O_RDWR0x0002;
182 break;
10
Execution continues on line 185
183 }
184
185 rd = open(radiodev, mode);
186 if (rd == -1)
11
Assuming the condition is false
12
Taking false branch
187 err(1, "%s open error", radiodev);
188
189 if (ioctl(rd, RIOCGINFO((unsigned long)0x40000000 | ((sizeof(struct radio_info) &
0x1fff) << 16) | ((('R')) << 8) | ((21)))
, &ri) == -1
)
13
Assuming the condition is false
14
Taking false branch
190 err(1, "RIOCGINFO");
191
192 if (!argc
14.1
'argc' is not equal to 0
&& show_vars)
193 print_vars(silent, show_choices);
194 else if (argc > 0 && !show_vars
15.1
'show_vars' is 0
) {
15
Assuming 'argc' is > 0
16
Taking true branch
195 if (mode
16.1
'mode' is equal to O_RDWR
== O_RDWR0x0002) {
17
Taking true branch
196 for (; argc--; argv++)
18
Loop condition is true. Entering loop body
39
Loop condition is true. Entering loop body
197 if (parse_opt(*argv, &opt))
19
Calling 'parse_opt'
37
Returned allocated memory
38
Taking false branch
40
Calling 'parse_opt'
198 do_ioctls(rd, &opt, silent);
199 } else {
200 for (; argc--; argv++)
201 if (parse_opt(*argv, &opt)) {
202 show_verbose(varname[opt.option],
203 silent);
204 print_value(opt.option, show_choices);
205 free(opt.string);
206 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
207 }
208 }
209 }
210
211 if (close(rd) == -1)
212 warn("%s close error", radiodev);
213
214 return 0;
215}
216
217void
218usage(void)
219{
220 fprintf(stderr(&__sF[2]),
221 "usage: %s [-anv] [-f file]\n"
222 " %s [-nv] [-f file] name\n"
223 " %s [-n] [-f file] name=value\n",
224 __progname, __progname, __progname);
225 exit(1);
226}
227
228void
229show_verbose(const char *nick, int silent)
230{
231 if (!silent)
232 printf("%s=", nick);
233}
234
235void
236warn_unsupported(int optval)
237{
238 warnx("driver does not support `%s'", varname[optval]);
239}
240
241void
242do_ioctls(int fd, struct opt_t *o, int silent)
243{
244 int oval;
245
246 if (fd < 0 || o == NULL((void *)0))
247 return;
248
249 if (o->option == OPTION_SEARCH0x00 && !(ri.caps & RADIO_CAPS_HW_SEARCH(1<<3))) {
250 warn_unsupported(o->option);
251 return;
252 }
253
254 oval = o->option == OPTION_SEARCH0x00 ? OPTION_FREQUENCY0x02 : o->option;
255 if (!silent)
256 printf("%s: ", varname[oval]);
257
258 print_value(o->option, 0);
259 printf(" -> ");
260
261 if (o->option == OPTION_SEARCH0x00) {
262
263 if (ioctl(fd, RIOCSSRCH((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('R')) << 8) | ((23)))
, &o->value) == -1) {
264 warn("RIOCSSRCH");
265 return;
266 }
267
268 } else {
269
270 change_value(*o);
271 if (ioctl(fd, RIOCSINFO(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct radio_info) & 0x1fff) << 16) | ((('R')) <<
8) | ((22)))
, &ri) == -1) {
272 warn("RIOCSINFO");
273 return;
274 }
275
276 }
277
278 if (ioctl(fd, RIOCGINFO((unsigned long)0x40000000 | ((sizeof(struct radio_info) &
0x1fff) << 16) | ((('R')) << 8) | ((21)))
, &ri) == -1) {
279 warn("RIOCGINFO");
280 return;
281 }
282
283 print_value(o->option, 0);
284 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
285}
286
287void
288change_value(const struct opt_t o)
289{
290 int unsupported = 0;
291
292 if (o.value == VALUE_NONE~0u)
293 return;
294
295 switch (o.option) {
296 case OPTION_VOLUME0x01:
297 update_value(o.sign, &ri.volume, o.value);
298 break;
299 case OPTION_FREQUENCY0x02:
300 ri.tuner_mode = RADIO_TUNER_MODE_RADIO(1<<0);
301 update_value(o.sign, &ri.freq, o.value);
302 break;
303 case OPTION_REFERENCE0x04:
304 if (ri.caps & RADIO_CAPS_REFERENCE_FREQ(1<<5))
305 update_value(o.sign, &ri.rfreq, o.value);
306 else
307 unsupported++;
308 break;
309 case OPTION_MONO0x05:
310 /* FALLTHROUGH */
311 case OPTION_STEREO0x06:
312 if (ri.caps & RADIO_CAPS_SET_MONO(1<<2))
313 ri.stereo = o.option == OPTION_MONO0x05 ? !o.value : o.value;
314 else
315 unsupported++;
316 break;
317 case OPTION_SENSITIVITY0x07:
318 if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY(1<<6))
319 update_value(o.sign, &ri.lock, o.value);
320 else
321 unsupported++;
322 break;
323 case OPTION_MUTE0x03:
324 ri.mute = o.value;
325 break;
326 case OPTION_CHANNEL0x08:
327 ri.tuner_mode = RADIO_TUNER_MODE_TV(1<<1);
328 update_value(o.sign, &ri.chan, o.value);
329 break;
330 case OPTION_CHNLSET0x09:
331 ri.chnlset = o.value;
332 break;
333 }
334
335 if (unsupported)
336 warn_unsupported(o.option);
337}
338
339/*
340 * Convert string to integer representation of a parameter
341 */
342int
343str_to_opt(const char *topt)
344{
345 int res, toptlen, varlen, len, varsize;
346
347 if (topt == NULL((void *)0) || *topt == '\0')
348 return OPTION_NONE~0u;
349
350 varsize = sizeof(varname) / sizeof(varname[0]);
351 toptlen = strlen(topt);
352
353 for (res = 0; res < varsize; res++) {
354 varlen = strlen(varname[res]);
355 len = toptlen > varlen ? toptlen : varlen;
356 if (strncmp(topt, varname[res], len) == 0)
357 return res;
358 }
359
360 warnx("bad name `%s'", topt);
361 return OPTION_NONE~0u;
362}
363
364void
365update_value(int sign, int *value, int update)
366{
367 switch (sign) {
368 case SIGN_NONE0:
369 *value = update;
370 break;
371 case SIGN_PLUS1:
372 *value += update;
373 break;
374 case SIGN_MINUS-1:
375 *value -= update;
376 break;
377 }
378}
379
380/*
381 * Convert string to unsigned integer
382 */
383u_int
384str_to_int(char *str, int optval)
385{
386 int val;
387
388 if (str == NULL((void *)0) || *str == '\0')
389 return VALUE_NONE~0u;
390
391 if (optval == OPTION_FREQUENCY0x02)
392 val = (int)(1000 * atof(str));
393 else
394 val = (int)strtol(str, (char **)NULL((void *)0), 10);
395
396 return val;
397}
398
399/*
400 * parse string s into struct opt_t
401 * return true on success, false on failure
402 */
403int
404parse_opt(char *s, struct opt_t *o) {
405 static const char badvalue[] = "bad value `%s'";
406 char *topt = NULL((void *)0);
407 int slen, optlen;
408
409 if (s == NULL((void *)0) || *s == '\0' || o
21.1
'o' is not equal to NULL
42.1
'o' is not equal to NULL
== NULL((void *)0))
20
Assuming 's' is not equal to NULL
21
Assuming the condition is false
22
Taking false branch
41
Assuming 's' is not equal to NULL
42
Assuming the condition is false
43
Taking false branch
410 return 0;
411
412 o->string = NULL((void *)0);
413 o->option = OPTION_NONE~0u;
44
Potential memory leak
414 o->value = VALUE_NONE~0u;
415 o->sign = SIGN_NONE0;
416
417 slen = strlen(s);
418 optlen = strcspn(s, "=");
419
420 /* Set only o->optval, the rest is missing */
421 if (slen == optlen) {
23
Assuming 'slen' is not equal to 'optlen'
24
Taking false branch
422 o->option = str_to_opt(s);
423 return o->option == OPTION_NONE~0u ? 0 : 1;
424 }
425
426 if (optlen > slen - 2) {
25
Assuming the condition is false
26
Taking false branch
427 warnx(badvalue, s);
428 return 0;
429 }
430
431 slen -= ++optlen;
432
433 if ((topt = malloc(optlen)) == NULL((void *)0)) {
27
Memory is allocated
28
Assuming the condition is false
29
Taking false branch
434 warn("memory allocation error");
435 return 0;
436 }
437 strlcpy(topt, s, optlen);
438
439 if ((o->option = str_to_opt(topt)) == OPTION_NONE~0u) {
30
Taking false branch
440 free(topt);
441 return 0;
442 }
443 o->string = topt;
444
445 topt = &s[optlen];
446
447 if (strcmp(o->string, "chnlset") == 0) {
31
Assuming the condition is false
32
Taking false branch
448 for (i = 0; chansets[i].name; i++)
449 if (strncmp(chansets[i].name, topt,
450 strlen(chansets[i].name)) == 0)
451 break;
452 if (chansets[i].name != NULL((void *)0)) {
453 o->value = chansets[i].value;
454 return 1;
455 } else {
456 warnx(badvalue, topt);
457 return 0;
458 }
459 }
460
461 switch (*topt) {
33
Control jumps to the 'default' case at line 483
462 case '+':
463 case '-':
464 o->sign = (*topt == '+') ? SIGN_PLUS1 : SIGN_MINUS-1;
465 o->value = str_to_int(&topt[1], o->option);
466 break;
467 case 'o':
468 if (strncmp(topt, offchar,
469 slen > OFFCHAR_LEN3 ? slen : OFFCHAR_LEN3) == 0)
470 o->value = 0;
471 else if (strncmp(topt, onchar,
472 slen > ONCHAR_LEN2 ? slen : ONCHAR_LEN2) == 0)
473 o->value = 1;
474 break;
475 case 'u':
476 if (strncmp(topt, "up", slen > 2 ? slen : 2) == 0)
477 o->value = 1;
478 break;
479 case 'd':
480 if (strncmp(topt, "down", slen > 4 ? slen : 4) == 0)
481 o->value = 0;
482 break;
483 default:
484 if (isdigit((unsigned char)*topt))
34
Taking false branch
485 o->value = str_to_int(topt, o->option);
486 break;
35
Execution continues on line 489
487 }
488
489 if (o->value == VALUE_NONE~0u) {
36
Taking true branch
490 warnx(badvalue, topt);
491 return 0;
492 }
493
494 return 1;
495}
496
497/*
498 * Print current value of the parameter.
499 */
500void
501print_value(int optval, int show_choices)
502{
503 if (optval == OPTION_NONE~0u)
504 return;
505
506 switch (optval) {
507 case OPTION_SEARCH0x00:
508 /* FALLTHROUGH */
509 case OPTION_FREQUENCY0x02:
510 printf("%.2fMHz", (float)ri.freq / 1000.);
511 break;
512 case OPTION_REFERENCE0x04:
513 printf("%ukHz", ri.rfreq);
514 break;
515 case OPTION_SENSITIVITY0x07:
516 printf("%umkV", ri.lock);
517 break;
518 case OPTION_MUTE0x03:
519 printf("%s", ri.mute ? onchar : offchar);
520 break;
521 case OPTION_MONO0x05:
522 printf("%s", ri.stereo ? offchar : onchar);
523 break;
524 case OPTION_STEREO0x06:
525 printf("%s", ri.stereo ? onchar : offchar);
526 break;
527 case OPTION_CHANNEL0x08:
528 printf("%u", ri.chan);
529 break;
530 case OPTION_CHNLSET0x09:
531 for (i = 0; chansets[i].name; i++) {
532 if (chansets[i].value == ri.chnlset)
533 printf("%s", chansets[i].name);
534 }
535 if (show_choices) {
536 printf("\n\t[");
537 for (i = 0; chansets[i].name; i++)
538 printf("%s ", chansets[i].name);
539 printf("]");
540 }
541 break;
542 case OPTION_VOLUME0x01:
543 default:
544 printf("%u", ri.volume);
545 break;
546 }
547}
548
549void
550show_int_val(int val, const char *nick, char *append, int silent)
551{
552 show_verbose(nick, silent);
553 printf("%u%s\n", val, append);
554}
555
556void
557show_float_val(float val, const char *nick, char *append, int silent)
558{
559 show_verbose(nick, silent);
560 printf("%.2f%s\n", val, append);
561}
562
563void
564show_char_val(const char *val, const char *nick, int silent)
565{
566 show_verbose(nick, silent);
567 printf("%s\n", val);
568}
569
570/*
571 * Print all available parameters
572 */
573void
574print_vars(int silent, int show_choices)
575{
576 show_int_val(ri.volume, varname[OPTION_VOLUME0x01], "", silent);
577 show_int_val(ri.chan, varname[OPTION_CHANNEL0x08], "", silent);
578 for (i = 0; chansets[i].name; i++) {
579 if (chansets[i].value == ri.chnlset)
580 show_char_val(chansets[i].name, varname[OPTION_CHNLSET0x09], silent);
581 }
582 if (show_choices) {
583 printf("\t[ ");
584 for (i = 0; chansets[i].name; i++)
585 printf("%s ", chansets[i].name);
586 printf("]\n");
587 }
588 show_float_val((float)ri.freq / 1000., varname[OPTION_FREQUENCY0x02],
589 "MHz", silent);
590 show_char_val(ri.mute ? onchar : offchar, varname[OPTION_MUTE0x03], silent);
591
592 if (ri.caps & RADIO_CAPS_REFERENCE_FREQ(1<<5))
593 show_int_val(ri.rfreq, varname[OPTION_REFERENCE0x04], "kHz", silent);
594 if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY(1<<6))
595 show_int_val(ri.lock, varname[OPTION_SENSITIVITY0x07], "mkV", silent);
596
597 if (ri.caps & RADIO_CAPS_DETECT_SIGNAL(1<<1)) {
598 show_verbose("signal", silent);
599 printf("%s\n", ri.info & RADIO_INFO_SIGNAL(1<<1) ? onchar : offchar);
600 }
601 if (ri.caps & RADIO_CAPS_DETECT_STEREO(1<<0)) {
602 show_verbose(varname[OPTION_STEREO0x06], silent);
603 printf("%s\n", ri.info & RADIO_INFO_STEREO(1<<0) ? onchar : offchar);
604 }
605
606 if (!silent) {
607 printf("mode: %s\n",
608 ri.tuner_mode == RADIO_TUNER_MODE_TV(1<<1) ? "TV" : "radio");
609
610 puts("card capabilities:");
611 }
612
613 if (ri.caps & RADIO_CAPS_SET_MONO(1<<2))
614 puts("\tmanageable mono/stereo");
615 if (ri.caps & RADIO_CAPS_HW_SEARCH(1<<3))
616 puts("\thardware search");
617 if (ri.caps & RADIO_CAPS_HW_AFC(1<<4))
618 puts("\thardware AFC");
619}