clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name diff.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/diff/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/diff/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/diff/diff.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | #include <sys/stat.h> |
24 | |
25 | #include <ctype.h> |
26 | #include <err.h> |
27 | #include <errno.h> |
28 | #include <getopt.h> |
29 | #include <stdlib.h> |
30 | #include <stdio.h> |
31 | #include <stdarg.h> |
32 | #include <string.h> |
33 | #include <unistd.h> |
34 | #include <limits.h> |
35 | |
36 | #include "diff.h" |
37 | #include "xmalloc.h" |
38 | |
39 | int Nflag, Pflag, rflag, sflag, Tflag; |
40 | int diff_format, diff_context, status; |
41 | char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; |
42 | struct stat stb1, stb2; |
43 | struct excludes *excludes_list; |
44 | regex_t ignore_re; |
45 | |
46 | #define OPTIONS "0123456789abC:cdD:efhI:iL:lnNPpqrS:sTtU:uwX:x:" |
47 | static struct option longopts[] = { |
48 | { "text", no_argument, 0, 'a' }, |
49 | { "ignore-space-change", no_argument, 0, 'b' }, |
50 | { "context", optional_argument, 0, 'C' }, |
51 | { "ifdef", required_argument, 0, 'D' }, |
52 | { "minimal", no_argument, 0, 'd' }, |
53 | { "ed", no_argument, 0, 'e' }, |
54 | { "forward-ed", no_argument, 0, 'f' }, |
55 | { "ignore-matching-lines", required_argument, 0, 'I' }, |
56 | { "ignore-case", no_argument, 0, 'i' }, |
57 | { "label", required_argument, 0, 'L' }, |
58 | { "new-file", no_argument, 0, 'N' }, |
59 | { "rcs", no_argument, 0, 'n' }, |
60 | { "unidirectional-new-file", no_argument, 0, 'P' }, |
61 | { "show-c-function", no_argument, 0, 'p' }, |
62 | { "brief", no_argument, 0, 'q' }, |
63 | { "recursive", no_argument, 0, 'r' }, |
64 | { "report-identical-files", no_argument, 0, 's' }, |
65 | { "starting-file", required_argument, 0, 'S' }, |
66 | { "expand-tabs", no_argument, 0, 't' }, |
67 | { "initial-tab", no_argument, 0, 'T' }, |
68 | { "unified", optional_argument, 0, 'U' }, |
69 | { "ignore-all-space", no_argument, 0, 'w' }, |
70 | { "exclude", required_argument, 0, 'x' }, |
71 | { "exclude-from", required_argument, 0, 'X' }, |
72 | { NULL, 0, 0, '\0'} |
73 | }; |
74 | |
75 | __dead void usage(void); |
76 | void push_excludes(char *); |
77 | void push_ignore_pats(char *); |
78 | void read_excludes_file(char *file); |
79 | void set_argstr(char **, char **); |
80 | |
81 | int |
82 | main(int argc, char **argv) |
83 | { |
84 | char *ep, **oargv; |
85 | long l; |
86 | int ch, dflags, lastch, gotstdin, prevoptind, newarg; |
87 | |
88 | oargv = argv; |
89 | gotstdin = 0; |
90 | dflags = 0; |
91 | lastch = '\0'; |
92 | prevoptind = 1; |
93 | newarg = 1; |
94 | while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { |
| 1 | Assuming the condition is true | |
|
| 2 | | Loop condition is true. Entering loop body | |
|
| 8 | | Assuming the condition is true | |
|
| 9 | | Loop condition is true. Entering loop body | |
|
95 | switch (ch) { |
| 3 | | Control jumps to 'case 85:' at line 183 | |
|
| 10 | | Control jumps to 'case 88:' at line 197 | |
|
96 | case '0': case '1': case '2': case '3': case '4': |
97 | case '5': case '6': case '7': case '8': case '9': |
98 | if (newarg) |
99 | usage(); |
100 | else if (lastch == 'c' || lastch == 'u') |
101 | diff_context = 0; |
102 | else if (!isdigit(lastch) || diff_context > INT_MAX / 10) |
103 | usage(); |
104 | diff_context = (diff_context * 10) + (ch - '0'); |
105 | break; |
106 | case 'a': |
107 | dflags |= D_FORCEASCII; |
108 | break; |
109 | case 'b': |
110 | dflags |= D_FOLDBLANKS; |
111 | break; |
112 | case 'C': |
113 | case 'c': |
114 | diff_format = D_CONTEXT; |
115 | if (optarg != NULL) { |
116 | l = strtol(optarg, &ep, 10); |
117 | if (*ep != '\0' || l < 0 || l >= INT_MAX) |
118 | usage(); |
119 | diff_context = (int)l; |
120 | } else |
121 | diff_context = 3; |
122 | break; |
123 | case 'd': |
124 | dflags |= D_MINIMAL; |
125 | break; |
126 | case 'D': |
127 | diff_format = D_IFDEF; |
128 | ifdefname = optarg; |
129 | break; |
130 | case 'e': |
131 | diff_format = D_EDIT; |
132 | break; |
133 | case 'f': |
134 | diff_format = D_REVERSE; |
135 | break; |
136 | case 'h': |
137 | |
138 | break; |
139 | case 'I': |
140 | push_ignore_pats(optarg); |
141 | break; |
142 | case 'i': |
143 | dflags |= D_IGNORECASE; |
144 | break; |
145 | case 'L': |
146 | if (label[0] == NULL) |
147 | label[0] = optarg; |
148 | else if (label[1] == NULL) |
149 | label[1] = optarg; |
150 | else |
151 | usage(); |
152 | break; |
153 | case 'N': |
154 | Nflag = 1; |
155 | break; |
156 | case 'n': |
157 | diff_format = D_NREVERSE; |
158 | break; |
159 | case 'p': |
160 | dflags |= D_PROTOTYPE; |
161 | break; |
162 | case 'P': |
163 | Pflag = 1; |
164 | break; |
165 | case 'r': |
166 | rflag = 1; |
167 | break; |
168 | case 'q': |
169 | diff_format = D_BRIEF; |
170 | break; |
171 | case 'S': |
172 | start = optarg; |
173 | break; |
174 | case 's': |
175 | sflag = 1; |
176 | break; |
177 | case 'T': |
178 | Tflag = 1; |
179 | break; |
180 | case 't': |
181 | dflags |= D_EXPANDTABS; |
182 | break; |
183 | case 'U': |
184 | case 'u': |
185 | diff_format = D_UNIFIED; |
186 | if (optarg != NULL) { |
| 4 | | Assuming 'optarg' is equal to NULL | |
|
| |
187 | l = strtol(optarg, &ep, 10); |
188 | if (*ep != '\0' || l < 0 || l >= INT_MAX) |
189 | usage(); |
190 | diff_context = (int)l; |
191 | } else |
192 | diff_context = 3; |
193 | break; |
| 6 | | Execution continues on line 207 | |
|
194 | case 'w': |
195 | dflags |= D_IGNOREBLANKS; |
196 | break; |
197 | case 'X': |
198 | read_excludes_file(optarg); |
| 11 | | Passing null pointer value via 1st parameter 'file' | |
|
| 12 | | Calling 'read_excludes_file' | |
|
199 | break; |
200 | case 'x': |
201 | push_excludes(optarg); |
202 | break; |
203 | default: |
204 | usage(); |
205 | break; |
206 | } |
207 | lastch = ch; |
208 | newarg = optind != prevoptind; |
| 7 | | Assuming 'optind' is equal to 'prevoptind' | |
|
209 | prevoptind = optind; |
210 | } |
211 | argc -= optind; |
212 | argv += optind; |
213 | |
214 | if (pledge("stdio rpath tmppath", NULL) == -1) |
215 | err(2, "pledge"); |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | if (argc != 2) |
222 | usage(); |
223 | if (ignore_pats != NULL) { |
224 | char buf[BUFSIZ]; |
225 | int error; |
226 | |
227 | if ((error = regcomp(&ignore_re, ignore_pats, |
228 | REG_NEWLINE | REG_EXTENDED)) != 0) { |
229 | regerror(error, &ignore_re, buf, sizeof(buf)); |
230 | if (*ignore_pats != '\0') |
231 | errx(2, "%s: %s", ignore_pats, buf); |
232 | else |
233 | errx(2, "%s", buf); |
234 | } |
235 | } |
236 | if (strcmp(argv[0], "-") == 0) { |
237 | fstat(STDIN_FILENO, &stb1); |
238 | gotstdin = 1; |
239 | } else if (stat(argv[0], &stb1) != 0) |
240 | err(2, "%s", argv[0]); |
241 | if (strcmp(argv[1], "-") == 0) { |
242 | fstat(STDIN_FILENO, &stb2); |
243 | gotstdin = 1; |
244 | } else if (stat(argv[1], &stb2) != 0) |
245 | err(2, "%s", argv[1]); |
246 | if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode))) |
247 | errx(2, "can't compare - to a directory"); |
248 | set_argstr(oargv, argv); |
249 | if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) { |
250 | if (diff_format == D_IFDEF) |
251 | errx(2, "-D option not supported with directories"); |
252 | diffdir(argv[0], argv[1], dflags); |
253 | } else { |
254 | if (S_ISDIR(stb1.st_mode)) { |
255 | argv[0] = splice(argv[0], argv[1]); |
256 | if (stat(argv[0], &stb1) == -1) |
257 | err(2, "%s", argv[0]); |
258 | } |
259 | if (S_ISDIR(stb2.st_mode)) { |
260 | argv[1] = splice(argv[1], argv[0]); |
261 | if (stat(argv[1], &stb2) == -1) |
262 | err(2, "%s", argv[1]); |
263 | } |
264 | print_status(diffreg(argv[0], argv[1], dflags), argv[0], argv[1], |
265 | ""); |
266 | } |
267 | exit(status); |
268 | } |
269 | |
270 | void |
271 | set_argstr(char **av, char **ave) |
272 | { |
273 | size_t argsize; |
274 | char **ap; |
275 | |
276 | argsize = 4 + *ave - *av + 1; |
277 | diffargs = xmalloc(argsize); |
278 | strlcpy(diffargs, "diff", argsize); |
279 | for (ap = av + 1; ap < ave; ap++) { |
280 | if (strcmp(*ap, "--") != 0) { |
281 | strlcat(diffargs, " ", argsize); |
282 | strlcat(diffargs, *ap, argsize); |
283 | } |
284 | } |
285 | } |
286 | |
287 | |
288 | |
289 | |
290 | void |
291 | read_excludes_file(char *file) |
292 | { |
293 | FILE *fp; |
294 | char *buf, *pattern; |
295 | size_t len; |
296 | |
297 | if (strcmp(file, "-") == 0) |
| 13 | | Null pointer passed as 1st argument to string comparison function |
|
298 | fp = stdin; |
299 | else if ((fp = fopen(file, "r")) == NULL) |
300 | err(2, "%s", file); |
301 | while ((buf = fgetln(fp, &len)) != NULL) { |
302 | if (buf[len - 1] == '\n') |
303 | len--; |
304 | pattern = xmalloc(len + 1); |
305 | memcpy(pattern, buf, len); |
306 | pattern[len] = '\0'; |
307 | push_excludes(pattern); |
308 | } |
309 | if (strcmp(file, "-") != 0) |
310 | fclose(fp); |
311 | } |
312 | |
313 | |
314 | |
315 | |
316 | void |
317 | push_excludes(char *pattern) |
318 | { |
319 | struct excludes *entry; |
320 | |
321 | entry = xmalloc(sizeof(*entry)); |
322 | entry->pattern = pattern; |
323 | entry->next = excludes_list; |
324 | excludes_list = entry; |
325 | } |
326 | |
327 | void |
328 | push_ignore_pats(char *pattern) |
329 | { |
330 | size_t len; |
331 | |
332 | if (ignore_pats == NULL) |
333 | ignore_pats = xstrdup(pattern); |
334 | else { |
335 | |
336 | len = strlen(ignore_pats) + strlen(pattern) + 2; |
337 | ignore_pats = xreallocarray(ignore_pats, 1, len); |
338 | strlcat(ignore_pats, "|", len); |
339 | strlcat(ignore_pats, pattern, len); |
340 | } |
341 | } |
342 | |
343 | void |
344 | print_only(const char *path, size_t dirlen, const char *entry) |
345 | { |
346 | if (dirlen > 1) |
347 | dirlen--; |
348 | printf("Only in %.*s: %s\n", (int)dirlen, path, entry); |
349 | } |
350 | |
351 | void |
352 | print_status(int val, char *path1, char *path2, char *entry) |
353 | { |
354 | switch (val) { |
355 | case D_BINARY: |
356 | printf("Binary files %s%s and %s%s differ\n", |
357 | path1, entry, path2, entry); |
358 | break; |
359 | case D_DIFFER: |
360 | if (diff_format == D_BRIEF) |
361 | printf("Files %s%s and %s%s differ\n", |
362 | path1, entry, path2, entry); |
363 | break; |
364 | case D_SAME: |
365 | if (sflag) |
366 | printf("Files %s%s and %s%s are identical\n", |
367 | path1, entry, path2, entry); |
368 | break; |
369 | case D_MISMATCH1: |
370 | printf("File %s%s is a directory while file %s%s is a regular file\n", |
371 | path1, entry, path2, entry); |
372 | break; |
373 | case D_MISMATCH2: |
374 | printf("File %s%s is a regular file while file %s%s is a directory\n", |
375 | path1, entry, path2, entry); |
376 | break; |
377 | case D_SKIPPED1: |
378 | printf("File %s%s is not a regular file or directory and was skipped\n", |
379 | path1, entry); |
380 | break; |
381 | case D_SKIPPED2: |
382 | printf("File %s%s is not a regular file or directory and was skipped\n", |
383 | path2, entry); |
384 | break; |
385 | } |
386 | } |
387 | |
388 | __dead void |
389 | usage(void) |
390 | { |
391 | (void)fprintf(stderr, |
392 | "usage: diff [-abdipTtw] [-c | -e | -f | -n | -q | -u] [-I pattern] [-L label]\n" |
393 | " file1 file2\n" |
394 | " diff [-abdipTtw] [-I pattern] [-L label] -C number file1 file2\n" |
395 | " diff [-abditw] [-I pattern] -D string file1 file2\n" |
396 | " diff [-abdipTtw] [-I pattern] [-L label] -U number file1 file2\n" |
397 | " diff [-abdiNPprsTtw] [-c | -e | -f | -n | -q | -u] [-I pattern]\n" |
398 | " [-L label] [-S name] [-X file] [-x pattern] dir1 dir2\n"); |
399 | |
400 | exit(2); |
401 | } |