clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name diffreg.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 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/tog/../include -I /home/ben/Projects/got/tog/../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/tog/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -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 -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/tog/../lib/diffreg.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | #include <sys/mman.h> |
19 | #include <sys/stat.h> |
20 | #include <sys/queue.h> |
21 | |
22 | #include <errno.h> |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | |
27 | #include "got_object.h" |
28 | #include "got_opentemp.h" |
29 | #include "got_error.h" |
30 | |
31 | #include "got_lib_diff.h" |
32 | |
33 | const struct diff_algo_config myers_then_patience; |
34 | const struct diff_algo_config myers_then_myers_divide; |
35 | const struct diff_algo_config patience; |
36 | const struct diff_algo_config myers_divide; |
37 | |
38 | const struct diff_algo_config myers_then_patience = (struct diff_algo_config){ |
39 | .impl = diff_algo_myers, |
40 | .permitted_state_size = 1024 * 1024 * sizeof(int), |
41 | .fallback_algo = &patience, |
42 | }; |
43 | |
44 | const struct diff_algo_config myers_then_myers_divide = |
45 | (struct diff_algo_config){ |
46 | .impl = diff_algo_myers, |
47 | .permitted_state_size = 1024 * 1024 * sizeof(int), |
48 | .fallback_algo = &myers_divide, |
49 | }; |
50 | |
51 | const struct diff_algo_config patience = (struct diff_algo_config){ |
52 | .impl = diff_algo_patience, |
53 | |
54 | .inner_algo = &patience, |
55 | |
56 | .fallback_algo = &myers_then_myers_divide, |
57 | }; |
58 | |
59 | const struct diff_algo_config myers_divide = (struct diff_algo_config){ |
60 | .impl = diff_algo_myers_divide, |
61 | |
62 | .inner_algo = &myers_then_myers_divide, |
63 | |
64 | }; |
65 | |
66 | |
67 | |
68 | const struct diff_config diff_config_myers_then_myers_divide = { |
69 | .atomize_func = diff_atomize_text_by_line, |
70 | .algo = &myers_then_myers_divide, |
71 | }; |
72 | |
73 | |
74 | |
75 | const struct diff_config diff_config_myers_then_patience = { |
76 | .atomize_func = diff_atomize_text_by_line, |
77 | .algo = &myers_then_patience, |
78 | }; |
79 | |
80 | |
81 | const struct diff_config diff_config_patience = { |
82 | .atomize_func = diff_atomize_text_by_line, |
83 | .algo = &patience, |
84 | }; |
85 | |
86 | |
87 | const struct diff_config diff_config_no_algo = { |
88 | .atomize_func = diff_atomize_text_by_line, |
89 | }; |
90 | |
91 | const struct got_error * |
92 | got_diffreg_close(FILE *f1, char *p1, size_t size1, |
93 | FILE *f2, char *p2, size_t size2) |
94 | { |
95 | const struct got_error *err = NULL; |
96 | |
97 | if (p1 && munmap(p1, size1) == -1 && err == NULL) |
98 | err = got_error_from_errno("munmap"); |
99 | if (p2 && munmap(p2, size2) == -1 && err == NULL) |
100 | err = got_error_from_errno("munmap"); |
101 | if (f1 && fclose(f1) == EOF && err == NULL) |
102 | err = got_error_from_errno("fclose"); |
103 | if (f2 && fclose(f2) == EOF && err == NULL) |
104 | err = got_error_from_errno("fclose"); |
105 | return err; |
106 | } |
107 | |
108 | const struct got_error * |
109 | got_diff_get_config(struct diff_config **cfg, |
110 | enum got_diff_algorithm algorithm, |
111 | diff_atomize_func_t atomize_func, void *atomize_func_data) |
112 | { |
113 | *cfg = calloc(1, sizeof(**cfg)); |
114 | if (*cfg == NULL) |
| 7 | | Assuming the condition is false | |
|
| |
115 | return got_error_from_errno("calloc"); |
116 | |
117 | switch (algorithm) { |
| 9 | | Control jumps to 'case GOT_DIFF_ALGORITHM_MYERS:' at line 121 | |
|
118 | case GOT_DIFF_ALGORITHM_PATIENCE: |
119 | (*cfg)->algo = &patience; |
120 | break; |
121 | case GOT_DIFF_ALGORITHM_MYERS: |
122 | (*cfg)->algo = &myers_then_myers_divide; |
123 | break; |
| 10 | | Execution continues on line 128 | |
|
124 | default: |
125 | return got_error_msg(GOT_ERR_NOT_IMPL, "bad diff algorithm"); |
126 | } |
127 | |
128 | if (atomize_func) { |
| |
129 | (*cfg)->atomize_func = atomize_func; |
130 | (*cfg)->atomize_func_data = atomize_func_data; |
131 | } else |
132 | (*cfg)->atomize_func = diff_atomize_text_by_line; |
133 | |
134 | (*cfg)->max_recursion_depth = 0; |
135 | |
136 | return NULL; |
| 12 | | Returning null pointer, which participates in a condition later | |
|
137 | } |
138 | |
139 | const struct got_error * |
140 | got_diff_prepare_file(FILE *f, char **p, size_t *size, |
141 | struct diff_data *diff_data, const struct diff_config *cfg, |
142 | int ignore_whitespace, int force_text_diff) |
143 | { |
144 | const struct got_error *err = NULL; |
145 | struct stat st; |
146 | int diff_flags = 0, rc; |
147 | |
148 | *size = 0; |
149 | |
150 | diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES; |
151 | if (ignore_whitespace) |
152 | diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE; |
153 | if (force_text_diff) |
154 | diff_flags |= DIFF_FLAG_FORCE_TEXT_DATA; |
155 | |
156 | if (fstat(fileno(f), &st) == -1) { |
157 | err = got_error_from_errno("fstat"); |
158 | goto done; |
159 | } |
160 | #ifndef GOT_DIFF_NO_MMAP |
161 | *p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, |
162 | fileno(f), 0); |
163 | if (*p == MAP_FAILED) |
164 | #endif |
165 | *p = NULL; |
166 | |
167 | rc = diff_atomize_file(diff_data, cfg, f, *p, st.st_size, diff_flags); |
168 | if (rc) { |
169 | err = got_error_set_errno(rc, "diff_atomize_file"); |
170 | goto done; |
171 | } |
172 | done: |
173 | if (err) |
174 | diff_data_free(diff_data); |
175 | else |
176 | *size = st.st_size; |
177 | return err; |
178 | } |
179 | |
180 | const struct got_error * |
181 | got_diffreg(struct got_diffreg_result **diffreg_result, FILE *f1, FILE *f2, |
182 | enum got_diff_algorithm algorithm, int ignore_whitespace, |
183 | int force_text_diff) |
184 | { |
185 | const struct got_error *err = NULL; |
186 | struct diff_config *cfg = NULL; |
187 | char *p1 = NULL, *p2 = NULL; |
188 | int f1_created = 0, f2_created = 0; |
189 | size_t size1, size2; |
| 1 | 'size2' declared without an initial value | |
|
190 | struct diff_data d_left, d_right; |
191 | struct diff_data *left, *right; |
192 | struct diff_result *diff_result; |
193 | |
194 | if (diffreg_result) { |
| 2 | | Assuming 'diffreg_result' is non-null | |
|
| |
195 | *diffreg_result = calloc(1, sizeof(**diffreg_result)); |
196 | if (*diffreg_result == NULL) |
| 4 | | Assuming the condition is false | |
|
| |
197 | return got_error_from_errno("calloc"); |
198 | left = &(*diffreg_result)->left; |
199 | right = &(*diffreg_result)->right; |
200 | } else { |
201 | memset(&d_left, 0, sizeof(d_left)); |
202 | memset(&d_right, 0, sizeof(d_right)); |
203 | left = &d_left; |
204 | right = &d_right; |
205 | } |
206 | |
207 | err = got_diff_get_config(&cfg, algorithm, NULL, NULL); |
| 6 | | Calling 'got_diff_get_config' | |
|
| 13 | | Returning from 'got_diff_get_config' | |
|
208 | if (err) |
| |
209 | goto done; |
210 | |
211 | if (f1 == NULL) { |
| 15 | | Assuming 'f1' is not equal to NULL | |
|
| |
212 | f1_created = 1; |
213 | f1 = got_opentemp(); |
214 | if (f1 == NULL) { |
215 | err = got_error_from_errno("got_opentemp"); |
216 | goto done; |
217 | } |
218 | } |
219 | if (f2 == NULL) { |
| 17 | | Assuming 'f2' is equal to NULL | |
|
| |
220 | f2_created = 1; |
221 | f2 = got_opentemp(); |
222 | if (f2 == NULL) { |
| 19 | | Assuming 'f2' is not equal to NULL | |
|
| |
223 | err = got_error_from_errno("got_opentemp"); |
224 | goto done; |
225 | } |
226 | } |
227 | |
228 | err = got_diff_prepare_file(f1, &p1, &size1, left, cfg, |
229 | ignore_whitespace, force_text_diff); |
230 | if (err) |
| 21 | | Assuming 'err' is non-null | |
|
| |
231 | goto done; |
| 23 | | Control jumps to line 260 | |
|
232 | |
233 | err = got_diff_prepare_file(f2, &p2, &size2, right, cfg, |
234 | ignore_whitespace, force_text_diff); |
235 | if (err) |
236 | goto done; |
237 | |
238 | diff_result = diff_main(cfg, left, right); |
239 | if (diff_result == NULL) { |
240 | err = got_error_set_errno(ENOMEM, "malloc"); |
241 | goto done; |
242 | } |
243 | if (diff_result->rc != DIFF_RC_OK) { |
244 | err = got_error_set_errno(diff_result->rc, "diff"); |
245 | goto done; |
246 | } |
247 | |
248 | if (diffreg_result) { |
249 | (*diffreg_result)->result = diff_result; |
250 | if (f1_created) |
251 | (*diffreg_result)->f1 = f1; |
252 | (*diffreg_result)->map1 = p1; |
253 | (*diffreg_result)->size1 = size1; |
254 | if (f2_created) |
255 | (*diffreg_result)->f2 = f2; |
256 | (*diffreg_result)->map2 = p2; |
257 | (*diffreg_result)->size2 = size2; |
258 | } |
259 | done: |
260 | free(cfg); |
261 | if (diffreg_result == NULL) { |
| |
262 | diff_data_free(left); |
263 | diff_data_free(right); |
264 | } |
265 | if (err) { |
| |
266 | got_diffreg_close(f1_created ? f1 : NULL, p1, size1, |
| |
| 28 | | 6th function call argument is an uninitialized value |
|
267 | f2_created ? f2 : NULL, p2, size2); |
| |
268 | if (diffreg_result) { |
269 | diff_data_free(left); |
270 | diff_data_free(right); |
271 | free(*diffreg_result); |
272 | *diffreg_result = NULL; |
273 | } |
274 | } |
275 | |
276 | return err; |
277 | } |
278 | |
279 | const struct got_error * |
280 | got_diffreg_output(off_t **line_offsets, size_t *nlines, |
281 | struct got_diffreg_result *diff_result, int f1_exists, int f2_exists, |
282 | const char *path1, const char *path2, |
283 | enum got_diff_output_format output_format, int context_lines, FILE *outfile) |
284 | { |
285 | struct diff_input_info info = { |
286 | .left_path = path1, |
287 | .right_path = path2, |
288 | .flags = 0, |
289 | }; |
290 | int rc; |
291 | struct diff_output_info *output_info; |
292 | |
293 | if (!f1_exists) |
294 | info.flags |= DIFF_INPUT_LEFT_NONEXISTENT; |
295 | if (!f2_exists) |
296 | info.flags |= DIFF_INPUT_RIGHT_NONEXISTENT; |
297 | |
298 | switch (output_format) { |
299 | case GOT_DIFF_OUTPUT_UNIDIFF: |
300 | rc = diff_output_unidiff( |
301 | line_offsets ? &output_info : NULL, outfile, &info, |
302 | diff_result->result, context_lines); |
303 | if (rc != DIFF_RC_OK) |
304 | return got_error_set_errno(rc, "diff_output_unidiff"); |
305 | break; |
306 | case GOT_DIFF_OUTPUT_EDSCRIPT: |
307 | rc = diff_output_edscript(line_offsets ? &output_info : NULL, |
308 | outfile, &info, diff_result->result); |
309 | if (rc != DIFF_RC_OK) |
310 | return got_error_set_errno(rc, "diff_output_edscript"); |
311 | break; |
312 | |
313 | } |
314 | |
315 | if (line_offsets && *line_offsets) { |
316 | if (output_info->line_offsets.len > 0) { |
317 | off_t prev_offset = 0, *p, *o; |
318 | int i, len; |
319 | if (*nlines > 0) { |
320 | prev_offset = (*line_offsets)[*nlines - 1]; |
321 | |
322 | |
323 | |
324 | |
325 | o = &output_info->line_offsets.head[1]; |
326 | len = output_info->line_offsets.len - 1; |
327 | } else { |
328 | o = &output_info->line_offsets.head[0]; |
329 | len = output_info->line_offsets.len; |
330 | } |
331 | p = reallocarray(*line_offsets, *nlines + len, |
332 | sizeof(off_t)); |
333 | if (p == NULL) |
334 | return got_error_from_errno("calloc"); |
335 | for (i = 0; i < len; i++) |
336 | p[*nlines + i] = o[i] + prev_offset; |
337 | *line_offsets = p; |
338 | *nlines += len; |
339 | } |
340 | diff_output_info_free(output_info); |
341 | } |
342 | |
343 | return NULL; |
344 | } |
345 | |
346 | const struct got_error * |
347 | got_diffreg_result_free(struct got_diffreg_result *diffreg_result) |
348 | { |
349 | const struct got_error *err; |
350 | |
351 | diff_result_free(diffreg_result->result); |
352 | diff_data_free(&diffreg_result->left); |
353 | diff_data_free(&diffreg_result->right); |
354 | err = got_diffreg_close(diffreg_result->f1, diffreg_result->map1, |
355 | diffreg_result->size1, diffreg_result->f2, |
356 | diffreg_result->map2, diffreg_result->size2); |
357 | free(diffreg_result); |
358 | return err; |
359 | } |
360 | |
361 | const struct got_error * |
362 | got_diffreg_result_free_left(struct got_diffreg_result *diffreg_result) |
363 | { |
364 | diff_data_free(&diffreg_result->left); |
365 | memset(&diffreg_result->left, 0, sizeof(diffreg_result->left)); |
366 | return got_diffreg_close(diffreg_result->f1, diffreg_result->map1, |
367 | diffreg_result->size1, NULL, NULL, 0); |
368 | } |
369 | |
370 | const struct got_error * |
371 | got_diffreg_result_free_right(struct got_diffreg_result *diffreg_result) |
372 | { |
373 | diff_data_free(&diffreg_result->right); |
374 | memset(&diffreg_result->right, 0, sizeof(diffreg_result->right)); |
375 | return got_diffreg_close(NULL, NULL, 0, diffreg_result->f2, |
376 | diffreg_result->map2, diffreg_result->size2); |
377 | } |