Bug Summary

File:src/usr.bin/sed/main.c
Warning:line 152, column 2
Value stored to 'argc' 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 main.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/sed/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/sed/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/sed/main.c
1/* $OpenBSD: main.c,v 1.42 2021/01/31 14:23:05 naddy Exp $ */
2
3/*-
4 * Copyright (c) 1992 Diomidis Spinellis.
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Diomidis Spinellis of Imperial College, University of London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/stat.h>
39
40#include <ctype.h>
41#include <errno(*__errno()).h>
42#include <fcntl.h>
43#include <limits.h>
44#include <regex.h>
45#include <stddef.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#include <libgen.h>
51
52#include "defs.h"
53#include "extern.h"
54
55/*
56 * Linked list of units (strings and files) to be compiled
57 */
58struct s_compunit {
59 struct s_compunit *next;
60 enum e_cut {CU_FILE, CU_STRING} type;
61 char *s; /* Pointer to string or fname */
62};
63
64/*
65 * Linked list pointer to compilation units and pointer to current
66 * next pointer.
67 */
68static struct s_compunit *script, **cu_nextp = &script;
69
70/*
71 * Linked list of files to be processed
72 */
73struct s_flist {
74 char *fname;
75 struct s_flist *next;
76};
77
78/*
79 * Linked list pointer to files and pointer to current
80 * next pointer.
81 */
82static struct s_flist *files, **fl_nextp = &files;
83
84FILE *infile; /* Current input file */
85FILE *outfile; /* Current output file */
86
87int Eflag, aflag, eflag, nflag;
88static int rval; /* Exit status */
89
90/*
91 * Current file and line number; line numbers restart across compilation
92 * units, but span across input files. The latter is optional if editing
93 * in place.
94 */
95const char *fname; /* File name. */
96const char *outfname; /* Output file name */
97static char oldfname[PATH_MAX1024]; /* Old file name (for in-place editing) */
98static char tmpfname[PATH_MAX1024]; /* Temporary file name (for in-place editing) */
99char *inplace; /* Inplace edit file extension */
100u_long linenum;
101
102static void add_compunit(enum e_cut, char *);
103static void add_file(char *);
104static int next_files_have_lines(void);
105
106int termwidth;
107
108int pledge_wpath, pledge_rpath;
109
110int
111main(int argc, char *argv[])
112{
113 struct winsize win;
114 int c, fflag;
115 char *p;
116
117 fflag = 0;
118 inplace = NULL((void*)0);
119 while ((c = getopt(argc, argv, "Eae:f:i::nru")) != -1)
120 switch (c) {
121 case 'E':
122 case 'r':
123 Eflag = 1;
124 break;
125 case 'a':
126 aflag = 1;
127 break;
128 case 'e':
129 eflag = 1;
130 add_compunit(CU_STRING, optarg);
131 break;
132 case 'f':
133 fflag = 1;
134 add_compunit(CU_FILE, optarg);
135 break;
136 case 'i':
137 inplace = optarg ? optarg : "";
138 break;
139 case 'n':
140 nflag = 1;
141 break;
142 case 'u':
143 setvbuf(stdout(&__sF[1]), NULL((void*)0), _IOLBF1, 0);
144 break;
145 default:
146 case '?':
147 (void)fprintf(stderr(&__sF[2]),
148 "usage: sed [-aEnru] [-i[extension]] command [file ...]\n"
149 " sed [-aEnru] [-e command] [-f command_file] [-i[extension]] [file ...]\n");
150 exit(1);
151 }
152 argc -= optind;
Value stored to 'argc' is never read
153 argv += optind;
154
155 termwidth = 0;
156 if ((p = getenv("COLUMNS")) != NULL((void*)0))
157 termwidth = strtonum(p, 0, INT_MAX2147483647, NULL((void*)0));
158 if (termwidth == 0 && ioctl(STDOUT_FILENO1, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &win) == 0 &&
159 win.ws_col > 0)
160 termwidth = win.ws_col;
161 if (termwidth == 0)
162 termwidth = 80;
163 if (termwidth <= 8)
164 termwidth = 1;
165 else
166 termwidth -= 8;
167
168 if (inplace != NULL((void*)0)) {
169 if (pledge("stdio rpath wpath cpath fattr chown", NULL((void*)0)) == -1)
170 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
171 } else {
172 if (pledge("stdio rpath wpath cpath", NULL((void*)0)) == -1)
173 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
174 }
175
176 /* First usage case; script is the first arg */
177 if (!eflag && !fflag && *argv) {
178 add_compunit(CU_STRING, *argv);
179 argv++;
180 }
181
182 compile();
183
184 /* Continue with first and start second usage */
185 if (*argv) {
186 if (!pledge_wpath && inplace == NULL((void*)0)) {
187 if (pledge("stdio rpath", NULL((void*)0)) == -1)
188 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
189 }
190 for (; *argv; argv++)
191 add_file(*argv);
192 } else {
193 if (!pledge_wpath && !pledge_rpath) {
194 if (pledge("stdio", NULL((void*)0)) == -1)
195 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
196 } else if (pledge_rpath) {
197 if (pledge("stdio rpath", NULL((void*)0)) == -1)
198 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
199 } else if (pledge_wpath) {
200 if (pledge("stdio wpath cpath", NULL((void*)0)) == -1)
201 error(FATAL1, "pledge: %s", strerror(errno(*__errno())));
202 }
203 add_file(NULL((void*)0));
204 }
205 process();
206 cfclose(prog, NULL((void*)0));
207 if (fclose(stdout(&__sF[1])))
208 error(FATAL1, "stdout: %s", strerror(errno(*__errno())));
209 exit (rval);
210}
211
212/*
213 * Like fgets, but go through the chain of compilation units chaining them
214 * together. Empty strings and files are ignored.
215 */
216char *
217cu_fgets(char **outbuf, size_t *outsize)
218{
219 static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
220 static FILE *f; /* Current open file */
221 static char *s; /* Current pointer inside string */
222 static char string_ident[30];
223 size_t len;
224 char *p;
225
226 if (*outbuf == NULL((void*)0))
227 *outsize = 0;
228
229again:
230 switch (state) {
231 case ST_EOF:
232 if (script == NULL((void*)0))
233 return (NULL((void*)0));
234 linenum = 0;
235 switch (script->type) {
236 case CU_FILE:
237 if ((f = fopen(script->s, "r")) == NULL((void*)0))
238 error(FATAL1,
239 "%s: %s", script->s, strerror(errno(*__errno())));
240 fname = script->s;
241 state = ST_FILE;
242 goto again;
243 case CU_STRING:
244 len = snprintf(string_ident, sizeof(string_ident),
245 "\"%s\"", script->s);
246 if (len >= sizeof(string_ident))
247 strlcpy(string_ident +
248 sizeof(string_ident) - 6, " ...\"", 5);
249 fname = string_ident;
250 s = script->s;
251 state = ST_STRING;
252 goto again;
253 }
254 case ST_FILE:
255 if (getline(outbuf, outsize, f) != -1) {
256 p = *outbuf;
257 linenum++;
258 if (linenum == 1 && p[0] == '#' && p[1] == 'n')
259 nflag = 1;
260 return (*outbuf);
261 }
262 script = script->next;
263 (void)fclose(f);
264 state = ST_EOF;
265 goto again;
266 case ST_STRING:
267 if (linenum == 0 && s[0] == '#' && s[1] == 'n')
268 nflag = 1;
269 p = *outbuf;
270 len = *outsize;
271 for (;;) {
272 if (len <= 1) {
273 *outbuf = xrealloc(*outbuf,
274 *outsize + _POSIX2_LINE_MAX2048);
275 p = *outbuf + *outsize - len;
276 len += _POSIX2_LINE_MAX2048;
277 *outsize += _POSIX2_LINE_MAX2048;
278 }
279 switch (*s) {
280 case '\0':
281 state = ST_EOF;
282 if (s == script->s) {
283 script = script->next;
284 goto again;
285 } else {
286 script = script->next;
287 *p = '\0';
288 linenum++;
289 return (*outbuf);
290 }
291 case '\n':
292 *p++ = '\n';
293 *p = '\0';
294 s++;
295 linenum++;
296 return (*outbuf);
297 default:
298 *p++ = *s++;
299 len--;
300 }
301 }
302 }
303
304 return (NULL((void*)0));
305}
306
307void
308finish_file(void)
309{
310 if (infile != NULL((void*)0)) {
311 fclose(infile);
312 if (*oldfname != '\0') {
313 if (rename(fname, oldfname) != 0) {
314 warning("rename()");
315 unlink(tmpfname);
316 exit(1);
317 }
318 *oldfname = '\0';
319 }
320 if (*tmpfname != '\0') {
321 if (outfile != NULL((void*)0) && outfile != stdout(&__sF[1]))
322 fclose(outfile);
323 outfile = NULL((void*)0);
324 rename(tmpfname, fname);
325 *tmpfname = '\0';
326 }
327 outfname = NULL((void*)0);
328 }
329}
330
331/*
332 * Like fgets, but go through the list of files chaining them together.
333 * Set len to the length of the line.
334 */
335int
336mf_fgets(SPACE *sp, enum e_spflag spflag)
337{
338 struct stat sb;
339 size_t len;
340 char dirbuf[PATH_MAX1024];
341 static char *p;
342 static size_t psize;
343 int c, fd;
344 static int firstfile;
345
346 if (infile == NULL((void*)0)) {
347 /* stdin? */
348 if (files->fname == NULL((void*)0)) {
349 if (inplace != NULL((void*)0))
350 error(FATAL1, "-i may not be used with stdin");
351 infile = stdin(&__sF[0]);
352 fname = "stdin";
353 outfile = stdout(&__sF[1]);
354 outfname = "stdout";
355 }
356
357 firstfile = 1;
358 }
359
360 for (;;) {
361 if (infile != NULL((void*)0) && (c = getc(infile)(!__isthreaded ? (--(infile)->_r < 0 ? __srget(infile) :
(int)(*(infile)->_p++)) : (getc)(infile))
) != EOF(-1)) {
362 (void)ungetc(c, infile);
363 break;
364 }
365 /* If we are here then either eof or no files are open yet */
366 if (infile == stdin(&__sF[0])) {
367 sp->len = 0;
368 return (0);
369 }
370 finish_file();
371 if (firstfile == 0)
372 files = files->next;
373 else
374 firstfile = 0;
375 if (files == NULL((void*)0)) {
376 sp->len = 0;
377 return (0);
378 }
379 fname = files->fname;
380 if (inplace != NULL((void*)0)) {
381 if (lstat(fname, &sb) != 0)
382 error(FATAL1, "%s: %s", fname,
383 strerror(errno(*__errno()) ? errno(*__errno()) : EIO5));
384 if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000))
385 error(FATAL1, "%s: %s %s", fname,
386 "in-place editing only",
387 "works for regular files");
388 if (*inplace != '\0') {
389 strlcpy(oldfname, fname,
390 sizeof(oldfname));
391 len = strlcat(oldfname, inplace,
392 sizeof(oldfname));
393 if (len > sizeof(oldfname))
394 error(FATAL1, "%s: name too long", fname);
395 }
396 strlcpy(dirbuf, fname, sizeof(dirbuf));
397 len = snprintf(tmpfname, sizeof(tmpfname),
398 "%s/sedXXXXXXXXXX", dirname(dirbuf));
399 if (len >= sizeof(tmpfname))
400 error(FATAL1, "%s: name too long", fname);
401 if ((fd = mkstemp(tmpfname)) == -1)
402 error(FATAL1, "%s: %s", fname, strerror(errno(*__errno())));
403 if ((outfile = fdopen(fd, "w")) == NULL((void*)0)) {
404 unlink(tmpfname);
405 error(FATAL1, "%s", fname);
406 }
407 fchown(fileno(outfile)(!__isthreaded ? ((outfile)->_file) : (fileno)(outfile)), sb.st_uid, sb.st_gid);
408 fchmod(fileno(outfile)(!__isthreaded ? ((outfile)->_file) : (fileno)(outfile)), sb.st_mode & ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007));
409 outfname = tmpfname;
410 linenum = 0;
411 resetstate();
412 } else {
413 outfile = stdout(&__sF[1]);
414 outfname = "stdout";
415 }
416 if ((infile = fopen(fname, "r")) == NULL((void*)0)) {
417 warning("%s", strerror(errno(*__errno())));
418 rval = 1;
419 continue;
420 }
421 }
422
423 /*
424 * We are here only when infile is open and we still have something
425 * to read from it.
426 *
427 * Use getline() so that we can handle essentially infinite input
428 * data. The p and psize are static so each invocation gives
429 * getline() the same buffer which is expanded as needed.
430 */
431 len = getline(&p, &psize, infile);
432 if ((ssize_t)len == -1)
433 error(FATAL1, "%s: %s", fname, strerror(errno(*__errno())));
434 if (len != 0 && p[len - 1] == '\n') {
435 sp->append_newline = 1;
436 len--;
437 } else if (!lastline()) {
438 sp->append_newline = 1;
439 } else {
440 sp->append_newline = 0;
441 }
442 cspace(sp, p, len, spflag);
443
444 linenum++;
445
446 return (1);
447}
448
449/*
450 * Add a compilation unit to the linked list
451 */
452static void
453add_compunit(enum e_cut type, char *s)
454{
455 struct s_compunit *cu;
456
457 cu = xmalloc(sizeof(struct s_compunit));
458 cu->type = type;
459 cu->s = s;
460 cu->next = NULL((void*)0);
461 *cu_nextp = cu;
462 cu_nextp = &cu->next;
463}
464
465/*
466 * Add a file to the linked list
467 */
468static void
469add_file(char *s)
470{
471 struct s_flist *fp;
472
473 fp = xmalloc(sizeof(struct s_flist));
474 fp->next = NULL((void*)0);
475 *fl_nextp = fp;
476 fp->fname = s;
477 fl_nextp = &fp->next;
478}
479
480
481static int
482next_files_have_lines()
483{
484 struct s_flist *file;
485 FILE *file_fd;
486 int ch;
487
488 file = files;
489 while ((file = file->next) != NULL((void*)0)) {
490 if ((file_fd = fopen(file->fname, "r")) == NULL((void*)0))
491 continue;
492
493 if ((ch = getc(file_fd)(!__isthreaded ? (--(file_fd)->_r < 0 ? __srget(file_fd
) : (int)(*(file_fd)->_p++)) : (getc)(file_fd))
) != EOF(-1)) {
494 /*
495 * This next file has content, therefore current
496 * file doesn't contains the last line.
497 */
498 ungetc(ch, file_fd);
499 fclose(file_fd);
500 return (1);
501 }
502 fclose(file_fd);
503 }
504 return (0);
505}
506
507int
508lastline(void)
509{
510 int ch;
511
512 if (feof(infile)(!__isthreaded ? (((infile)->_flags & 0x0020) != 0) : (
feof)(infile))
) {
513 return !(
514 (inplace == NULL((void*)0)) &&
515 next_files_have_lines());
516 }
517 if ((ch = getc(infile)(!__isthreaded ? (--(infile)->_r < 0 ? __srget(infile) :
(int)(*(infile)->_p++)) : (getc)(infile))
) == EOF(-1)) {
518 return !(
519 (inplace == NULL((void*)0)) &&
520 next_files_have_lines());
521 }
522 ungetc(ch, infile);
523 return (0);
524}