Bug Summary

File:src/usr.bin/vi/build/../ex/ex_read.c
Warning:line 280, column 7
Branch condition evaluates to a garbage 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 ex_read.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/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/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/vi/build/../ex/ex_read.c
1/* $OpenBSD: ex_read.c,v 1.14 2017/04/18 01:45:35 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12#include "config.h"
13
14#include <sys/types.h>
15#include <sys/queue.h>
16#include <sys/stat.h>
17#include <sys/time.h>
18
19#include <bitstring.h>
20#include <ctype.h>
21#include <errno(*__errno()).h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "../common/common.h"
28#include "../vi/vi.h"
29
30/*
31 * ex_read -- :read [file]
32 * :read [!cmd]
33 * Read from a file or utility.
34 *
35 * !!!
36 * Historical vi wouldn't undo a filter read, for no apparent reason.
37 *
38 * PUBLIC: int ex_read(SCR *, EXCMD *);
39 */
40int
41ex_read(SCR *sp, EXCMD *cmdp)
42{
43 enum { R_ARG, R_EXPANDARG, R_FILTER } which;
44 struct stat sb;
45 CHAR_T *arg, *name;
46 EX_PRIVATE *exp;
47 FILE *fp;
48 FREF *frp;
49 GS *gp;
50 MARK rm;
51 recno_t nlines;
1
'nlines' declared without an initial value
52 size_t arglen;
53 int argc, rval;
54 char *p;
55
56 gp = sp->gp;
57
58 /*
59 * 0 args: read the current pathname.
60 * 1 args: check for "read !arg".
61 */
62 switch (cmdp->argc) {
2
Control jumps to 'case 1:' at line 68
63 case 0:
64 which = R_ARG;
65 arg = NULL((void *)0); /* unused */
66 arglen = 0; /* unused */
67 break;
68 case 1:
69 arg = cmdp->argv[0]->bp;
70 arglen = cmdp->argv[0]->len;
71 if (*arg == '!') {
3
Assuming the condition is false
4
Taking false branch
72 ++arg;
73 --arglen;
74 which = R_FILTER;
75
76 /* Secure means no shell access. */
77 if (O_ISSET(sp, O_SECURE)((((&(((sp)))->opts[(((O_SECURE)))])->flags) & (
(0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_SECURE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_SECURE)))]
.o_cur.val)
) {
78 ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
79 return (1);
80 }
81 } else
82 which = R_EXPANDARG;
83 break;
5
Execution continues on line 90
84 default:
85 abort();
86 /* NOTREACHED */
87 }
88
89 /* Load a temporary file if no file being edited. */
90 if (sp->ep == NULL((void *)0)) {
6
Assuming field 'ep' is not equal to NULL
7
Taking false branch
91 if ((frp = file_add(sp, NULL((void *)0))) == NULL((void *)0))
92 return (1);
93 if (file_init(sp, frp, NULL((void *)0), 0))
94 return (1);
95 }
96
97 switch (which) {
8
Control jumps to 'case R_EXPANDARG:' at line 189
98 case R_FILTER:
99 /*
100 * File name and bang expand the user's argument. If
101 * we don't get an additional argument, it's illegal.
102 */
103 argc = cmdp->argc;
104 if (argv_exp1(sp, cmdp, arg, arglen, 1))
105 return (1);
106 if (argc == cmdp->argc) {
107 ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
108 return (1);
109 }
110 argc = cmdp->argc - 1;
111
112 /* Set the last bang command. */
113 exp = EXP(sp)((EX_PRIVATE *)((sp)->ex_private));
114 free(exp->lastbcomm);
115 if ((exp->lastbcomm =
116 strdup(cmdp->argv[argc]->bp)) == NULL((void *)0)) {
117 msgq(sp, M_SYSERR, NULL((void *)0));
118 return (1);
119 }
120
121 /*
122 * Vi redisplayed the user's argument if it changed, ex
123 * always displayed a !, plus the user's argument if it
124 * changed.
125 */
126 if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
127 if (F_ISSET(cmdp, E_MODIFY)(((cmdp)->flags) & ((0x00200000))))
128 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
129 } else {
130 if (F_ISSET(cmdp, E_MODIFY)(((cmdp)->flags) & ((0x00200000))))
131 (void)ex_printf(sp,
132 "!%s\n", cmdp->argv[argc]->bp);
133 else
134 (void)ex_puts(sp, "!\n");
135 (void)ex_fflush(sp);
136 }
137
138 /*
139 * Historically, filter reads as the first ex command didn't
140 * wait for the user. If SC_SCR_EXWROTE not already set, set
141 * the don't-wait flag.
142 */
143 if (!F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010))))
144 F_SET(sp, SC_EX_WAIT_NO)(((sp)->flags) |= ((0x00080000)));
145
146 /*
147 * Switch into ex canonical mode. The reason to restore the
148 * original terminal modes for read filters is so that users
149 * can do things like ":r! cat /dev/tty".
150 *
151 * !!!
152 * We do not output an extra <newline>, so that we don't touch
153 * the screen on a normal read.
154 */
155 if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
156 if (gp->scr_screen(sp, SC_EX0x00000001)) {
157 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
158 return (1);
159 }
160 /*
161 * !!!
162 * Historically, the read command doesn't switch to
163 * the alternate X11 xterm screen, if doing a filter
164 * read -- don't set SA_ALTERNATE.
165 */
166 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE)(((sp)->flags) |= ((0x00000004 | 0x00000010)));
167 }
168
169 if (ex_filter(sp, cmdp, &cmdp->addr1,
170 NULL((void *)0), &rm, cmdp->argv[argc]->bp, FILTER_READ))
171 return (1);
172
173 /* The filter version of read set the autoprint flag. */
174 F_SET(cmdp, E_AUTOPRINT)(((cmdp)->flags) |= ((0x00000040)));
175
176 /*
177 * If in vi mode, move to the first nonblank. Might have
178 * switched into ex mode, so saved the original SC_VI value.
179 */
180 sp->lno = rm.lno;
181 if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
182 sp->cno = 0;
183 (void)nonblank(sp, sp->lno, &sp->cno);
184 }
185 return (0);
186 case R_ARG:
187 name = sp->frp->name;
188 break;
189 case R_EXPANDARG:
190 if (argv_exp2(sp, cmdp, arg, arglen))
9
Assuming the condition is false
10
Taking false branch
191 return (1);
192 /*
193 * 0 args: impossible.
194 * 1 args: impossible (I hope).
195 * 2 args: read it.
196 * >2 args: object, too many args.
197 *
198 * The 1 args case depends on the argv_sexp() function refusing
199 * to return success without at least one non-blank character.
200 */
201 switch (cmdp->argc) {
11
Control jumps to 'case 2:' at line 206
202 case 0:
203 case 1:
204 abort();
205 /* NOTREACHED */
206 case 2:
207 name = cmdp->argv[1]->bp;
208 /*
209 * !!!
210 * Historically, the read and write commands renamed
211 * "unnamed" files, or, if the file had a name, set
212 * the alternate file name.
213 */
214 if (F_ISSET(sp->frp, FR_TMPFILE)(((sp->frp)->flags) & ((0x0080))) &&
12
Assuming the condition is false
215 !F_ISSET(sp->frp, FR_EXNAMED)(((sp->frp)->flags) & ((0x0004)))) {
216 if ((p = v_strdup(sp, cmdp->argv[1]->bp,
217 cmdp->argv[1]->len)) != NULL((void *)0)) {
218 free(sp->frp->name);
219 sp->frp->name = p;
220 }
221 /*
222 * The file has a real name, it's no longer a
223 * temporary, clear the temporary file flags.
224 */
225 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE)(((sp->frp)->flags) &= ~((0x0040 | 0x0080)));
226 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED)(((sp->frp)->flags) |= ((0x0008 | 0x0004)));
227
228 /* Notify the screen. */
229 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
230 } else
231 set_alt_name(sp, name);
232 break;
13
Execution continues on line 238
233 default:
234 ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
235 return (1);
236
237 }
238 break;
14
Execution continues on line 252
239 default:
240 abort();
241 /* NOTREACHED */
242 }
243
244 /*
245 * !!!
246 * Historically, vi did not permit reads from non-regular files, nor
247 * did it distinguish between "read !" and "read!", so there was no
248 * way to "force" it. We permit reading from named pipes too, since
249 * they didn't exist when the original implementation of vi was done
250 * and they seem a reasonable addition.
251 */
252 if ((fp = fopen(name, "r")) == NULL((void *)0) || fstat(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), &sb)) {
15
Assuming the condition is false
16
Assuming '__isthreaded' is 0
17
'?' condition is true
18
Assuming the condition is false
19
Taking false branch
253 msgq_str(sp, M_SYSERR, name, "%s");
254 return (1);
255 }
256 if (!S_ISFIFO(sb.st_mode)((sb.st_mode & 0170000) == 0010000) && !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) {
20
Assuming the condition is true
257 (void)fclose(fp);
258 msgq(sp, M_ERR,
259 "Only regular files and named pipes may be read");
260 return (1);
261 }
262
263 /* Try and get a lock. */
264 if (file_lock(sp, NULL((void *)0), NULL((void *)0), fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), 0) == LOCK_UNAVAIL)
21
'?' condition is true
22
Assuming the condition is false
23
Taking false branch
265 msgq(sp, M_ERR, "%s: read lock was unavailable", name);
266
267 rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
24
Calling 'ex_readfp'
32
Returning from 'ex_readfp'
268
269 /*
270 * In vi, set the cursor to the first line read in, if anything read
271 * in, otherwise, the address. (Historic vi set it to the line after
272 * the address regardless, but since that line may not exist we don't
273 * bother.)
274 *
275 * In ex, set the cursor to the last line read in, if anything read in,
276 * otherwise, the address.
277 */
278 if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
33
Assuming the condition is true
34
Taking true branch
279 sp->lno = cmdp->addr1.lno;
280 if (nlines)
35
Branch condition evaluates to a garbage value
281 ++sp->lno;
282 } else
283 sp->lno = cmdp->addr1.lno + nlines;
284 return (rval);
285}
286
287/*
288 * ex_readfp --
289 * Read lines into the file.
290 *
291 * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int);
292 */
293int
294ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp,
295 int silent)
296{
297 EX_PRIVATE *exp;
298 GS *gp;
299 recno_t lcnt, lno;
300 size_t len;
301 u_long ccnt; /* XXX: can't print off_t portably. */
302 int nf, rval;
303 char *p;
304
305 gp = sp->gp;
306 exp = EXP(sp)((EX_PRIVATE *)((sp)->ex_private));
307
308 /*
309 * Add in the lines from the output. Insertion starts at the line
310 * following the address.
311 */
312 ccnt = 0;
313 lcnt = 0;
314 p = "Reading...";
315 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
25
Assuming the condition is false
26
Loop condition is false. Execution continues on line 330
316 if ((lcnt + 1) % INTERRUPT_CHECK100 == 0) {
317 if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get
((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)->
flags) & ((0x0004)))))
)
318 break;
319 if (!silent) {
320 gp->scr_busy(sp, p,
321 p == NULL((void *)0) ? BUSY_UPDATE : BUSY_ON);
322 p = NULL((void *)0);
323 }
324 }
325 if (db_append(sp, 1, lno, exp->ibp, len))
326 goto err;
327 ccnt += len;
328 }
329
330 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
|| fclose(fp))
27
'?' condition is true
28
Assuming the condition is true
331 goto err;
29
Control jumps to line 347
332
333 /* Return the number of lines read in. */
334 if (nlinesp != NULL((void *)0))
335 *nlinesp = lcnt;
336
337 if (!silent) {
338 p = msg_print(sp, name, &nf);
339 msgq(sp, M_INFO,
340 "%s: %lu lines, %lu characters", p, lcnt, ccnt);
341 if (nf)
342 FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(p); }
;
343 }
344
345 rval = 0;
346 if (0) {
347err: msgq_str(sp, M_SYSERR, name, "%s");
348 (void)fclose(fp);
349 rval = 1;
350 }
351
352 if (!silent
29.1
'silent' is 0
)
30
Taking true branch
353 gp->scr_busy(sp, NULL((void *)0), BUSY_OFF);
354 return (rval);
31
Returning without writing to '*nlinesp'
355}