Bug Summary

File:src/usr.bin/tput/tput.c
Warning:line 258, column 6
2nd function call argument is an uninitialized value

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 tput.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/tput/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/tput/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/tput/tput.c
1/* $OpenBSD: tput.c,v 1.24 2019/01/25 00:19:27 millert Exp $ */
2
3/*
4 * Copyright (c) 1999 Todd C. Miller <millert@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 * Copyright (c) 1980, 1988, 1993
20 * The Regents of the University of California. All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47#include <ctype.h>
48#include <err.h>
49#include <curses.h>
50#include <term.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <termios.h>
54#include <unistd.h>
55#include <errno(*__errno()).h>
56#include <limits.h>
57#include <string.h>
58
59#define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
60
61#include <sys/wait.h>
62
63static void init(void);
64static char **process(char *, char *, char **);
65static void reset(void);
66static void set_margins(void);
67static void usage(void);
68
69extern char *__progname;
70
71int
72main(int argc, char *argv[])
73{
74 int ch, exitval, n, Sflag;
75 size_t len;
76 char *p, *term, *str;
77 char **oargv;
78
79 if (pledge("stdio rpath wpath tty", NULL((void *)0)) == -1)
1
Assuming the condition is false
2
Taking false branch
80 err(1, "pledge");
81
82 oargv = argv;
83 term = NULL((void *)0);
84 Sflag = exitval = 0;
85 while ((ch = getopt(argc, argv, "ST:")) != -1)
3
Assuming the condition is false
4
Loop condition is false. Execution continues on line 97
86 switch(ch) {
87 case 'T':
88 term = optarg;
89 break;
90 case 'S':
91 Sflag = 1;
92 break;
93 case '?':
94 default:
95 usage();
96 }
97 argc -= optind;
98 argv += optind;
99
100 if (Sflag
4.1
'Sflag' is 0
&& argc > 0)
101 usage();
102
103 if (!term
4.2
'term' is null
&& !(term = getenv("TERM")))
5
Assuming 'term' is non-null
6
Taking false branch
104 errx(2, "No value for $TERM and no -T specified");
105
106 /*
107 * NOTE: tgetent() will call setupterm() and set ospeed for us
108 * (this is ncurses-specific behavior)
109 */
110 if (tgetent(NULL((void *)0), term) != 1)
7
Assuming the condition is false
8
Taking false branch
111 errx(3, "Unknown terminal type `%s'", term);
112
113 if (strcmp(__progname, "clear") == 0) {
9
Assuming the condition is false
10
Taking false branch
114 if (Sflag)
115 usage();
116 argv = oargv;
117 *argv = __progname;
118 *(argv+1) = NULL((void *)0);
119 }
120 if (Sflag
10.1
'Sflag' is 0
) {
11
Taking false branch
121 char **av;
122
123 /* Build new argv based on stdin */
124 argc = n = 0;
125 av = NULL((void *)0);
126 while ((str = fgetln(stdin(&__sF[0]), &len)) != NULL((void *)0)) {
127 if (str[len-1] != '\n')
128 errx(1, "premature EOF");
129 str[len-1] = '\0';
130 while ((p = strsep(&str, " \t")) != NULL((void *)0)) {
131 /* grow av as needed */
132 if (argc + 1 >= n) {
133 n += 64;
134 av = reallocarray(av, n,
135 sizeof(char *));
136 if (av == NULL((void *)0))
137 errx(1, "out of memory");
138 }
139 if (*p != '\0' &&
140 (av[argc++] = strdup(p)) == NULL((void *)0))
141 errx(1, "out of memory");
142 }
143 }
144 if (argc > 0) {
145 av[argc] = NULL((void *)0);
146 argv = av;
147 }
148 }
149 while ((p = *argv++)) {
12
Loop condition is true. Entering loop body
150 switch (*p) {
13
'Default' branch taken. Execution continues on line 172
151 case 'i':
152 if (!strcmp(p, "init")) {
153 init();
154 continue;
155 }
156 break;
157 case 'l':
158 if (!strcmp(p, "longname")) {
159 puts(longname());
160 continue;
161 }
162 break;
163 case 'r':
164 if (!strcmp(p, "reset")) {
165 reset();
166 continue;
167 }
168 break;
169 }
170
171 /* First try as terminfo */
172 if ((str = tigetstr(p)) && str != (char *)-1)
14
Assuming 'str' is non-null
15
Assuming the condition is true
16
Taking true branch
173 argv = process(p, str, argv);
17
Calling 'process'
174 else if ((n = tigetnum(p)) != -2)
175 (void)printf("%d\n", n);
176 else if ((n = tigetflag(p)) != -1)
177 exitval = !n;
178 /* Then fall back on termcap */
179 else if ((str = tgetstr(p, NULL((void *)0))))
180 argv = process(p, str, argv);
181 else if ((n = tgetnum(p)) != -1)
182 (void)printf("%d\n", n);
183 else if ((exitval = tgetflag(p)) != 0)
184 exitval = !exitval;
185 else {
186 warnx("Unknown terminfo capability `%s'", p);
187 exitval = 4;
188 }
189 }
190 exit(exitval);
191}
192
193static char **
194process(char *cap, char *str, char **argv)
195{
196 char *cp, *s, *nargv[9];
197 int arg_need, popcount, i;
198
199 /* Count how many values we need for this capability. */
200 for (cp = str, arg_need = popcount = 0; *cp != '\0'; cp++) {
18
Assuming the condition is false
19
Loop condition is false. Execution continues on line 237
201 if (*cp == '%') {
202 switch (*++cp) {
203 case '%':
204 cp++;
205 break;
206 case 'i':
207 if (popcount < 2)
208 popcount = 2;
209 break;
210 case 'p':
211 cp++;
212 if (isdigit((unsigned char)cp[1]) &&
213 popcount < cp[1] - '0')
214 popcount = cp[1] - '0';
215 break;
216 case 'd':
217 case 's':
218 case '0':
219 case '1':
220 case '2':
221 case '3':
222 case '4':
223 case '5':
224 case '6':
225 case '7':
226 case '8':
227 case '9':
228 case '.':
229 case '+':
230 arg_need++;
231 break;
232 default:
233 break;
234 }
235 }
236 }
237 arg_need = MAXIMUM(arg_need, popcount)(((arg_need) > (popcount)) ? (arg_need) : (popcount));
20
'?' condition is false
238 if (arg_need
20.1
'arg_need' is <= 9
> 9)
21
Taking false branch
239 errx(2, "too many arguments (%d) for capability `%s'",
240 arg_need, cap);
241
242 for (i = 0; i < arg_need; i++) {
22
Loop condition is false. Execution continues on line 258
243 long l;
244
245 if (argv[i] == NULL((void *)0))
246 errx(2, "not enough arguments (%d) for capability `%s'",
247 arg_need, cap);
248
249 /* convert ascii representation of numbers to longs */
250 if (isdigit((unsigned char)argv[i][0])
251 && (l = strtol(argv[i], &cp, 10)) >= 0
252 && l < LONG_MAX9223372036854775807L && *cp == '\0')
253 nargv[i] = (char *)l;
254 else
255 nargv[i] = argv[i];
256 }
257
258 s = tparm(str, nargv[0], nargv[1], nargv[2], nargv[3],
23
2nd function call argument is an uninitialized value
259 nargv[4], nargv[5], nargv[6], nargv[7], nargv[8]);
260 putp(s);
261 fflush(stdout(&__sF[1]));
262
263 return (argv + arg_need);
264}
265
266static void
267init(void)
268{
269 FILE *ifile;
270 size_t len;
271 char *buf;
272 int wstatus;
273 pid_t pid;
274
275 if (init_progcur_term->type. Strings[138] && !issetugid()) {
276 switch (pid = vfork()) {
277 case -1:
278 err(4, "vfork");
279 break;
280 case 0:
281 /* child */
282 execl(init_progcur_term->type. Strings[138], init_progcur_term->type. Strings[138], (char *)NULL((void *)0));
283 _exit(127);
284 break;
285 default:
286 while (waitpid(pid, &wstatus, 0) == -1) {
287 if (errno(*__errno()) != EINTR4)
288 break;
289 }
290 /* parent */
291 break;
292 }
293 }
294 if (init_1stringcur_term->type. Strings[48])
295 putp(init_1stringcur_term->type. Strings[48]);
296 if (init_2stringcur_term->type. Strings[49])
297 putp(init_2stringcur_term->type. Strings[49]);
298 set_margins();
299 /* always use 8 space tabs */
300 if (init_tabscur_term->type. Numbers[1] != 8 && clear_all_tabscur_term->type. Strings[4] && set_tabcur_term->type. Strings[132]) {
301 int i;
302
303 putp(clear_all_tabscur_term->type. Strings[4]);
304 for (i = 0; i < (columnscur_term->type. Numbers[0] - 1) / 8; i++) {
305 if (parm_right_cursorcur_term->type. Strings[112])
306 putp(tparm(parm_right_cursorcur_term->type. Strings[112], 8));
307 else
308 fputs(" ", stdout(&__sF[1]));
309 putp(set_tabcur_term->type. Strings[132]);
310 }
311 }
312 if (init_filecur_term->type. Strings[51] && !issetugid() && (ifile = fopen(init_filecur_term->type. Strings[51], "r"))) {
313 while ((buf = fgetln(ifile, &len)) != NULL((void *)0)) {
314 if (buf[len-1] != '\n')
315 errx(1, "premature EOF reading %s", init_filecur_term->type. Strings[51]);
316 buf[len-1] = '\0';
317 putp(buf);
318 }
319 fclose(ifile);
320 }
321 if (init_3stringcur_term->type. Strings[50])
322 putp(init_3stringcur_term->type. Strings[50]);
323 fflush(stdout(&__sF[1]));
324}
325
326static void
327reset(void)
328{
329 FILE *rfile;
330 size_t len;
331 char *buf;
332
333 if (reset_1stringcur_term->type. Strings[122])
334 putp(reset_1stringcur_term->type. Strings[122]);
335 if (reset_2stringcur_term->type. Strings[123])
336 putp(reset_2stringcur_term->type. Strings[123]);
337 set_margins();
338 if (reset_filecur_term->type. Strings[125] && !issetugid() && (rfile = fopen(reset_filecur_term->type. Strings[125], "r"))) {
339 while ((buf = fgetln(rfile, &len)) != NULL((void *)0)) {
340 if (buf[len-1] != '\n')
341 errx(1, "premature EOF reading %s", reset_filecur_term->type. Strings[125]);
342 buf[len-1] = '\0';
343 putp(buf);
344 }
345 fclose(rfile);
346 }
347 if (reset_3stringcur_term->type. Strings[124])
348 putp(reset_3stringcur_term->type. Strings[124]);
349 fflush(stdout(&__sF[1]));
350}
351
352static void
353set_margins(void)
354{
355
356 /*
357 * Four possibilities:
358 * 1) we have set_lr_margin and can set things with one call
359 * 2) we have set_{left,right}_margin_parm, use two calls
360 * 3) we have set_{left,right}_margin, set based on position
361 * 4) none of the above, leave things the way they are
362 */
363 if (set_lr_margincur_term->type. Strings[368]) {
364 putp(tparm(set_lr_margincur_term->type. Strings[368], 0, columnscur_term->type. Numbers[0] - 1));
365 } else if (set_left_margin_parmcur_term->type. Strings[342] && set_right_margin_parmcur_term->type. Strings[343]) {
366 putp(tparm(set_left_margin_parmcur_term->type. Strings[342], 0));
367 putp(tparm(set_right_margin_parmcur_term->type. Strings[343], columnscur_term->type. Numbers[0] - 1));
368 } else if (set_left_margincur_term->type. Strings[271] && set_right_margincur_term->type. Strings[272] && clear_marginscur_term->type. Strings[270]) {
369 putp(clear_marginscur_term->type. Strings[270]);
370
371 /* go to column 0 and set the left margin */
372 putp(carriage_returncur_term->type. Strings[2] ? carriage_returncur_term->type. Strings[2] : "\r");
373 putp(set_left_margincur_term->type. Strings[271]);
374
375 /* go to last column and set the right margin */
376 if (parm_right_cursorcur_term->type. Strings[112])
377 putp(tparm(parm_right_cursorcur_term->type. Strings[112], columnscur_term->type. Numbers[0] - 1));
378 else
379 printf("%*s", columnscur_term->type. Numbers[0] - 1, " ");
380 putp(set_right_margincur_term->type. Strings[272]);
381 putp(carriage_returncur_term->type. Strings[2] ? carriage_returncur_term->type. Strings[2] : "\r");
382 }
383 fflush(stdout(&__sF[1]));
384}
385
386static void
387usage(void)
388{
389
390 if (strcmp(__progname, "clear") == 0)
391 (void)fprintf(stderr(&__sF[2]), "usage: %s [-T term]\n", __progname);
392 else
393 (void)fprintf(stderr(&__sF[2]),
394 "usage: %s [-T term] attribute [attribute-args] ...\n"
395 " %s [-T term] -S\n", __progname, __progname);
396 exit(1);
397}